diff --git a/.claude/commands/review-pending-prs.md b/.claude/commands/review-pending-prs.md new file mode 100644 index 000000000..a026ce92e --- /dev/null +++ b/.claude/commands/review-pending-prs.md @@ -0,0 +1,70 @@ +--- +description: Review pending PRs against CONTRIBUTING.md acceptance criteria. +allowed-tools: Bash(gh api:*), Bash(gh pr close:*), Bash(gh pr diff:*), Bash(gh pr edit:*), Bash(gh pr list:*) +--- + +## Usage + +``` +/review-pending-prs +``` + +## Instructions + +1. Fetch 10 open PRs with details: `gh pr list --repo vinta/awesome-python --limit 10 --search "-label:\"claude reviewed\"" --json number,title,author,url,body,files,mergeable,mergeStateStatus` +2. Fetch all PR diffs in parallel: `gh pr diff --repo vinta/awesome-python` +3. Run quick rejection checks (no API calls needed): + - Has merge conflicts? (from `mergeable`/`mergeStateStatus`) + - Adds more than one project? (from diff) + - Duplicate entry? (from diff - URL already in README) + - Not a project submission? (from diff - e.g., random files, contributor list) +4. For PRs passing quick checks, fetch repo stats: `gh api repos// --jq '{stars: .stargazers_count, created: .created_at, updated: .pushed_at, language: .language, archived: .archived}'` +5. Review against all criteria in [CONTRIBUTING.md](../../CONTRIBUTING.md) +6. Present summary table with recommendations +7. Ask user: + +``` +Would you like me to: + +1. Close the rejected PRs with comments? +2. Add "claude reviewed" label to the passed PRs? +3. Do all +``` + +## Quick Rejection Checks + +Check these rules first - if any fail, recommend rejection: + +- PR has merge conflicts +- Add more than one project per PR +- Duplicate of existing entry +- Placed under an inappropriate category +- Project is archived or abandoned (no commits in 12+ months) +- No documentation or unclear use case +- Less than 100 GitHub stars AND not justified as a hidden gem +- Too niche — a thin wrapper, single-function utility, or narrow edge-case tool that most Python developers would never need + +## Output Format + +Provide a simple review: + +1. **Rejection Check** - table with the above rules and PASS/REJECT +2. **Recommendation** - PASS or REJECT + +## Close PRs + +If user asks to close/reject: + +```bash +gh pr close --repo vinta/awesome-python --comment "" +``` + +## Mark as Passed + +```bash +gh pr edit --repo vinta/awesome-python --add-label "claude reviewed" +``` + +## Extra Instructions (If Provided) + +$ARGUMENTS diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 000000000..73febfbf3 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,18 @@ +{ + "permissions": { + "allow": [ + "Bash(gh api:*)", + "Bash(gh pr close:*)", + "Bash(gh pr comment:*)", + "Bash(gh pr diff:*)", + "Bash(gh pr edit:*)", + "Bash(gh pr list:*)", + "Bash(gh pr view:*)", + "Bash(gh run list:*)", + "Bash(gh run rerun:*)", + "Bash(gh run view:*)", + "Bash(gh search:*)" + ], + "deny": [] + } +} diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8feada4e8..f88b55341 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,24 @@ -## What is this Python project? +## Project -Describe features. +[Project Name](url) -## What's the difference between this Python project and similar ones? +## Checklist -Enumerate comparisons. +- [ ] One project per PR +- [ ] PR title format: `Add project-name` +- [ ] Entry format: `* [project-name](url) - Description ending with period.` +- [ ] Description is concise and short --- +## Why This Project Is Awesome -Anyone who agrees with this pull request could vote for it by adding a :+1: to it, and usually, the maintainer will merge it when votes reach **20**. +Which criterion does it meet? (pick one) + +- [ ] **Industry Standard** - The go-to tool for a specific use case +- [ ] **Rising Star** - 5000+ stars in < 2 years, significant adoption +- [ ] **Hidden Gem** - Exceptional quality, solves niche problems elegantly + +Explain: + +## How It Differs + +If similar entries exist, what makes this one unique? diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml new file mode 100644 index 000000000..8b7b0c7b7 --- /dev/null +++ b/.github/workflows/deploy-website.yml @@ -0,0 +1,80 @@ +name: Deploy Website + +on: + push: + branches: + - master + schedule: + - cron: "0 0 * * *" + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + + - name: Install dependencies + run: uv sync --group build + + - name: Restore star data cache + id: cache-stars + uses: actions/cache/restore@v4 + with: + path: website/data/github_stars.json + key: github-stars-${{ github.run_id }} + restore-keys: github-stars- + + - name: Fetch GitHub stars + id: fetch-stars + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: make fetch_github_stars + + - name: Save star data cache + if: steps.fetch-stars.outcome == 'success' + uses: actions/cache/save@v4 + with: + path: website/data/github_stars.json + key: github-stars-${{ github.run_id }} + + - name: Verify star data exists + run: | + if [ ! -f website/data/github_stars.json ]; then + echo "::error::github_stars.json not found. No cache and fetch failed or was skipped." + exit 1 + fi + echo "Star data found: $(wc -l < website/data/github_stars.json) lines" + + - name: Build site + run: make build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v4 + with: + path: website/output/ + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: https://awesome-python.com/ + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 4046e40f0..dd9781c3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,16 @@ +# macOS .DS_Store +# python +.venv/ *.py[co] -docs/index.md -site/ +# website +website/output/ +website/data/ + +# claude code +.claude/skills/ +.superpowers/ +.gstack/ +skills-lock.json diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f2cfce4d9..000000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: python - -python: - - "3.6" - -script: - - cp README.md docs/index.md - - mkdocs build - -deploy: - provider: pages - local-dir: site - skip-cleanup: true - keep-history: true - github-token: $GITHUB_TOKEN - on: - branch: master diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..81d13417c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,32 @@ +# CLAUDE.md + +## Repository Overview + +This is the awesome-python repository - a curated list of Python frameworks, libraries, software and resources. The repository serves as a comprehensive directory about Python ecosystem. + +## PR Review Guidelines + +**For all PR review tasks, refer to [CONTRIBUTING.md](CONTRIBUTING.md)** which contains: + +- Acceptance criteria (Industry Standard, Rising Star, Hidden Gem) +- Quality requirements +- Automatic rejection criteria +- Entry format reference +- PR description template + +## Architecture & Structure + +The repository follows a single-file architecture: + +- **README.md**: All content in hierarchical structure (categories, subcategories, entries) +- **CONTRIBUTING.md**: Submission guidelines and review criteria +- **sort.py**: Script to enforce alphabetical ordering + +Entry format: `* [project-name](url) - Concise description ending with period.` + +## Key Considerations + +- This is a curated list, not a code project +- Quality over quantity - only "awesome" projects +- Alphabetical ordering within categories is mandatory +- README.md is the source of truth for all content diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bcb24bfa6..1164e1288 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,17 +1,109 @@ # Contributing -Your contributions are always welcome! - -## Guidelines - -* Add one link per Pull Request. -* Add the link: `* [project-name](http://example.com/) - A short description ends with a period.` - * Keep descriptions concise. -* Add a section if needed. - * Add the section description. - * Add the section title to Table of Contents. -* Search previous suggestions before making a new one, as yours may be a duplicate. -* Don't mention `Python` in the description as it's implied. -* Check your spelling and grammar. -* Remove any trailing whitespace. -* Send a Pull Request with the reason why the library is awesome. +## Quality Requirements + +All submissions must satisfy **ALL** of these: + +1. **Python-first**: Primarily written in Python (>50% of codebase) +2. **Active**: Commits within the last 12 months +3. **Stable**: Production-ready, not alpha/beta/experimental +4. **Documented**: Clear README with examples and use cases +5. **Unique**: Adds distinct value, not "yet another X" +6. **Established**: Repository at least 1 month old + +## Acceptance Criteria + +Your submission must meet **ONE** of the following criteria: + +### 1. Industry Standard + +- The go-to tool that almost everyone uses for a specific use case +- Examples: requests, flask, pandas, numpy +- Limit: 1-3 tools per category + +### 2. Rising Star + +- Rapid growth: 5,000+ GitHub stars in less than 2 years +- Significant community buzz and adoption +- Solving problems in new or better ways +- Examples: fastapi, ruff, uv + +### 3. Hidden Gem + +- Exceptional quality despite fewer stars (100-500 stars preferred; < 100 requires strong justification) +- Solves niche problems elegantly +- Strong recommendation from experienced developers +- **Must demonstrate real-world usage** (not a project published last week) +- Repository must be at least 6 months old with consistent activity +- Must include compelling justification in PR description + +## Entry Format Reference + +**Use GitHub repository URLs** whenever possible. Projects linked to a GitHub repo are ranked higher on [awesome-python.com](https://awesome-python.com/). + +### Naming Convention + +Use the **PyPI package name** as the display name so developers can copy it directly to `pip install`. Check the canonical name at `https://pypi.org/pypi/{package}/json`. If the project is not on PyPI, use the GitHub repository name instead. + +### Standard Entry + +```markdown +- [pypi-name](https://github.com/owner/repo) - Description ending with period. +``` + +### Standard Library Module + +```markdown +- [module](https://docs.python.org/3/library/module.html) - (Python standard library) Description. +``` + +### Fork of Another Project + +```markdown +- [new-name](https://github.com/owner/new-name) - Description ([original-name](original-url) fork). +``` + +### Entry with Related Awesome List + +```markdown +- [project](https://github.com/owner/project) - Description. + - [awesome-project](https://github.com/someone/awesome-project) +``` + +### Subcategory Format + +```markdown +- Subcategory Name + - [project](url) - Description. +``` + +## Adding a New Section + +1. Add section description in italics: `*Libraries for doing X.*` +2. Add the section title to the Table of Contents +3. Keep sections in alphabetical order + +## Review Process + +PRs are reviewed by automated tools and maintainers: + +1. **Format Check**: Entry follows the correct format +2. **Category Check**: Placed in the appropriate category/subcategory +3. **Duplicate Check**: Not already listed or previously rejected +4. **Activity Check**: Project shows recent activity +5. **Quality Check**: Meets acceptance criteria + +Search previous Pull Requests and Issues before submitting, as yours may be a duplicate. + +## Automatic Rejection + +PRs will be **closed** if: + +- Adding multiple projects in one PR +- Duplicate of existing entry or recently-closed PR +- Empty or placeholder PR descriptions +- Placed under an inappropriate category +- Project is archived or abandoned (no commits in 12+ months) +- No documentation or unclear use case +- Less than 100 GitHub stars without Hidden Gem justification +- Repository less than 3 months old diff --git a/Makefile b/Makefile index eda7a8ff3..21a4c5d28 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,24 @@ -site_install: - pip install -r requirements.txt +-include .env +export -site_link: - ln -sf $(CURDIR)/README.md $(CURDIR)/docs/index.md +install: + uv sync -site_preview: site_link - mkdocs serve +fetch_github_stars: + uv run python website/fetch_github_stars.py -site_build: site_link - mkdocs build +test: + uv run pytest website/tests/ -v -site_deploy: site_link - mkdocs gh-deploy --clean +build: + uv run python website/build.py + +preview: build + @echo "Check the website on http://localhost:8000" + uv run watchmedo shell-command \ + --patterns='*.md;*.html;*.css;*.js;*.py' \ + --recursive \ + --wait --drop \ + --command='uv run python website/build.py' \ + README.md website/templates website/static website/data & \ + python -m http.server -b 127.0.0.1 -d website/output/ 8000 diff --git a/README.md b/README.md index 01df35403..5fac645bb 100644 --- a/README.md +++ b/README.md @@ -1,1294 +1,1219 @@ -# Awesome Python [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome) - -A curated list of awesome Python frameworks, libraries, software and resources. - -Inspired by [awesome-php](https://github.com/ziadoz/awesome-php). - -- [Awesome Python](#awesome-python) - - [Admin Panels](#admin-panels) - - [Algorithms and Design Patterns](#algorithms-and-design-patterns) - - [Audio](#audio) - - [Authentication](#authentication) - - [Build Tools](#build-tools) - - [Built-in Classes Enhancement](#built-in-classes-enhancement) - - [Caching](#caching) - - [ChatOps Tools](#chatops-tools) - - [CMS](#cms) - - [Code Analysis](#code-analysis) - - [Command-line Tools](#command-line-tools) - - [Compatibility](#compatibility) - - [Computer Vision](#computer-vision) - - [Concurrency and Parallelism](#concurrency-and-parallelism) - - [Configuration](#configuration) - - [Cryptography](#cryptography) - - [Data Analysis](#data-analysis) - - [Data Validation](#data-validation) - - [Data Visualization](#data-visualization) - - [Database Drivers](#database-drivers) - - [Database](#database) - - [Date and Time](#date-and-time) - - [Debugging Tools](#debugging-tools) - - [Deep Learning](#deep-learning) - - [DevOps Tools](#devops-tools) - - [Distributed Computing](#distributed-computing) - - [Distribution](#distribution) - - [Documentation](#documentation) - - [Downloader](#downloader) - - [E-commerce](#e-commerce) - - [Editor Plugins and IDEs](#editor-plugins-and-ides) - - [Email](#email) - - [Environment Management](#environment-management) - - [Files](#files) - - [Foreign Function Interface](#foreign-function-interface) - - [Forms](#forms) - - [Functional Programming](#functional-programming) - - [Game Development](#game-development) - - [Geolocation](#geolocation) - - [GUI](#gui) - - [Hardware](#hardware) - - [HTML Manipulation](#html-manipulation) - - [HTTP](#http) - - [Image Processing](#image-processing) - - [Implementations](#implementations) - - [Interactive Interpreter](#interactive-interpreter) - - [Internationalization](#internationalization) - - [Job Scheduler](#job-scheduler) - - [Logging](#logging) - - [Machine Learning](#machine-learning) - - [Miscellaneous](#miscellaneous) - - [Natural Language Processing](#natural-language-processing) - - [Network Virtualization](#network-virtualization) - - [Networking](#networking) - - [News Feed](#news-feed) - - [ORM](#orm) - - [Package Management](#package-management) - - [Package Repositories](#package-repositories) - - [Permissions](#permissions) - - [Processes](#processes) - - [Queue](#queue) - - [Recommender Systems](#recommender-systems) - - [RESTful API](#restful-api) - - [Robotics](#robotics) - - [RPC Servers](#rpc-servers) - - [Science](#science) - - [Search](#search) - - [Serialization](#serialization) - - [Serverless Frameworks](#serverless-frameworks) - - [Specific Formats Processing](#specific-formats-processing) - - [Static Site Generator](#static-site-generator) - - [Tagging](#tagging) - - [Template Engine](#template-engine) - - [Testing](#testing) - - [Text Processing](#text-processing) - - [Third-party APIs](#third-party-apis) - - [URL Manipulation](#url-manipulation) - - [Video](#video) - - [Web Asset Management](#web-asset-management) - - [Web Content Extracting](#web-content-extracting) - - [Web Crawling & Web Scraping](#web-crawling--web-scraping) - - [Web Frameworks](#web-frameworks) - - [WebSocket](#websocket) - - [WSGI Servers](#wsgi-servers) -- [Services](#services) - - [Code Quality](#code-quality) - - [Continuous Integration](#continuous-integration) -- [Resources](#resources) - - [Podcasts](#podcasts) - - [Twitter](#twitter) - - [Websites](#websites) - - [Weekly](#weekly) -- [Other Awesome Lists](#other-awesome-lists) -- [Contributing](#contributing) +# Awesome Python + +An opinionated list of awesome Python frameworks, libraries, tools, software and resources. + +> The **#10 most-starred repo on GitHub**. Put your product where Python developers discover tools. [Become a sponsor](SPONSORSHIP.md). + +# Categories + +- [Admin Panels](#admin-panels) +- [AI and Agents](#ai-and-agents) +- [Algorithms and Design Patterns](#algorithms-and-design-patterns) +- [ASGI Servers](#asgi-servers) +- [Asynchronous Programming](#asynchronous-programming) +- [Audio](#audio) +- [Authentication](#authentication) +- [Build Tools](#build-tools) +- [Built-in Classes Enhancement](#built-in-classes-enhancement) +- [Caching](#caching) +- [CMS](#cms) +- [Code Analysis](#code-analysis) +- [Command-line Interface Development](#command-line-interface-development) +- [Command-line Tools](#command-line-tools) +- [Computer Vision](#computer-vision) +- [Configuration Files](#configuration-files) +- [Cryptography](#cryptography) +- [Data Analysis](#data-analysis) +- [Data Validation](#data-validation) +- [Data Visualization](#data-visualization) +- [Database Drivers](#database-drivers) +- [Database](#database) +- [Date and Time](#date-and-time) +- [Debugging Tools](#debugging-tools) +- [Deep Learning](#deep-learning) +- [DevOps Tools](#devops-tools) +- [Distributed Computing](#distributed-computing) +- [Distribution](#distribution) +- [Documentation](#documentation) +- [Downloader](#downloader) +- [Editor Plugins and IDEs](#editor-plugins-and-ides) +- [Email](#email) +- [Environment Management](#environment-management) +- [File Manipulation](#file-manipulation) +- [Functional Programming](#functional-programming) +- [Game Development](#game-development) +- [Geolocation](#geolocation) +- [GUI Development](#gui-development) +- [Hardware](#hardware) +- [HTML Manipulation](#html-manipulation) +- [HTTP Clients](#http-clients) +- [Image Processing](#image-processing) +- [Implementations](#implementations) +- [Interactive Interpreter](#interactive-interpreter) +- [Internationalization](#internationalization) +- [Job Scheduler](#job-scheduler) +- [Logging](#logging) +- [Machine Learning](#machine-learning) +- [Miscellaneous](#miscellaneous) +- [Natural Language Processing](#natural-language-processing) +- [Network Virtualization](#network-virtualization) +- [ORM](#orm) +- [Package Management](#package-management) +- [Package Repositories](#package-repositories) +- [Penetration testing](#penetration-testing) +- [Permissions](#permissions) +- [Processes](#processes) +- [Quantum Computing](#quantum-computing) +- [Recommender Systems](#recommender-systems) +- [Refactoring](#refactoring) +- [RESTful API](#restful-api) +- [Robotics](#robotics) +- [RPC Servers](#rpc-servers) +- [Science](#science) +- [Search](#search) +- [Serialization](#serialization) +- [Serverless Frameworks](#serverless-frameworks) +- [Shell](#shell) +- [Specific Formats Processing](#specific-formats-processing) +- [Static Site Generator](#static-site-generator) +- [Task Queues](#task-queues) +- [Template Engine](#template-engine) +- [Testing](#testing) +- [Text Processing](#text-processing) +- [URL Manipulation](#url-manipulation) +- [Video](#video) +- [Web Asset Management](#web-asset-management) +- [Web Content Extracting](#web-content-extracting) +- [Web Crawling](#web-crawling) +- [Web Frameworks](#web-frameworks) +- [WebSocket](#websocket) +- [WSGI Servers](#wsgi-servers) --- ## Admin Panels -*Libraries for administrative interfaces.* +_Libraries for administrative interfaces._ -* [ajenti](https://github.com/ajenti/ajenti) - The admin panel your servers deserve. -* [django-grappelli](http://grappelliproject.com) - A jazzy skin for the Django Admin-Interface. -* [django-suit](http://djangosuit.com/) - Alternative Django Admin-Interface (free only for Non-commercial use). -* [django-xadmin](https://github.com/sshwsfc/xadmin) - Drop-in replacement of Django admin comes with lots of goodies. -* [flask-admin](https://github.com/flask-admin/flask-admin) - Simple and extensible administrative interface framework for Flask. -* [flower](https://github.com/mher/flower) - Real-time monitor and web admin for Celery. -* [wooey](https://github.com/wooey/wooey) - A Django app which creates automatic web UIs for Python scripts. +- [ajenti](https://github.com/ajenti/ajenti) - The admin panel your servers deserve. +- [django-grappelli](https://github.com/sehmaschine/django-grappelli) - A jazzy skin for the Django Admin-Interface. +- [django-unfold](https://github.com/unfoldadmin/django-unfold) - Elevate your Django admin with a stunning modern interface, powerful features, and seamless user experience. +- [flask-admin](https://github.com/flask-admin/flask-admin) - Simple and extensible administrative interface framework for Flask. +- [flower](https://github.com/mher/flower) - Real-time monitor and web admin for Celery. +- [func-to-web](https://github.com/offerrall/FuncToWeb) - Instantly create web UIs from Python functions using type hints. Zero frontend code required. +- [jet-bridge](https://github.com/jet-admin/jet-bridge) - Admin panel framework for any application with nice UI (ex Jet Django). +- [wooey](https://github.com/wooey/wooey) - A Django app which creates automatic web UIs for Python scripts. + +## AI and Agents + +_Libraries for building AI applications, LLM integrations, and autonomous agents._ + +- [agno](https://github.com/agno-agi/agno) - Open-source Python library for building AI agents and agentic systems. +- [autoresearch](https://github.com/karpathy/autoresearch) - AI agents running autonomous research experiments on single-GPU LLM training. +- [instructor](https://github.com/567-labs/instructor) - A library for extracting structured data from LLMs, powered by Pydantic. +- [langchain](https://github.com/langchain-ai/langchain) - Building applications with LLMs through composability. +- [llama_index](https://github.com/run-llama/llama_index) - A data framework for your LLM application. +- [praisonai](https://github.com/MervinPraison/PraisonAI) - Production-ready Multi-AI Agents framework with self-reflection, 100+ LLM support, MCP integration, and agentic workflows. +- [pydantic-ai](https://github.com/pydantic/pydantic-ai) - A Python agent framework for building generative AI applications with structured schemas. +- [ragflow](https://github.com/infiniflow/ragflow) - An open-source RAG engine for document understanding and question answering with LLMs. ## Algorithms and Design Patterns -*Python implementation of algorithms and design patterns.* +_Python implementation of data structures, algorithms and design patterns. Also see [awesome-algorithms](https://github.com/tayllan/awesome-algorithms)._ + +- Algorithms + - [algorithms](https://github.com/keon/algorithms) - Minimal examples of data structures and algorithms. + - [python-ds](https://github.com/prabhupant/python-ds) - A collection of data structure and algorithms for coding interviews. + - [sortedcontainers](https://github.com/grantjenks/python-sortedcontainers) - Fast and pure-Python implementation of sorted collections. + - [thealgorithms](https://github.com/TheAlgorithms/Python) - All Algorithms implemented in Python. +- Design Patterns + - [python-cqrs](https://github.com/vadikko2/python-cqrs) - Event-Driven Architecture Framework with CQRS/CQS, Transaction Outbox, Saga orchestration. + - [python-patterns](https://github.com/faif/python-patterns) - A collection of design patterns in Python. + - [transitions](https://github.com/pytransitions/transitions) - A lightweight, object-oriented finite state machine implementation. + +## ASGI Servers + +_[ASGI](https://asgi.readthedocs.io/en/latest/)-compatible web servers._ + +- [daphne](https://github.com/django/daphne) - A HTTP, HTTP2 and WebSocket protocol server for ASGI and ASGI-HTTP. +- [granian](https://github.com/emmett-framework/granian) - A Rust HTTP server for Python applications built on top of Hyper and Tokio, supporting WSGI/ASGI/RSGI. +- [hypercorn](https://github.com/pgjones/hypercorn) - An ASGI and WSGI Server based on Hyper libraries and inspired by Gunicorn. +- [uvicorn](https://github.com/encode/uvicorn) - A lightning-fast ASGI server implementation, using uvloop and httptools. + +## Asynchronous Programming -* [algorithms](https://github.com/keon/algorithms) - Minimal examples of data structures and algorithms in Python. -* [PyPattyrn](https://github.com/tylerlaberge/PyPattyrn) - A simple yet effective library for implementing common design patterns. -* [python-patterns](https://github.com/faif/python-patterns) - A collection of design patterns in Python. -* [sortedcontainers](http://www.grantjenks.com/docs/sortedcontainers/) - Fast, pure-Python implementation of SortedList, SortedDict, and SortedSet types. +_Libraries for asynchronous, concurrent and parallel execution. Also see [awesome-asyncio](https://github.com/timofurrer/awesome-asyncio)._ + +- [asyncio](https://docs.python.org/3/library/asyncio.html) - (Python standard library) Asynchronous I/O, event loop, coroutines and tasks. + - [awesome-asyncio](https://github.com/timofurrer/awesome-asyncio) +- [concurrent.futures](https://docs.python.org/3/library/concurrent.futures.html) - (Python standard library) A high-level interface for asynchronously executing callables. +- [gevent](https://github.com/gevent/gevent) - A coroutine-based Python networking library that uses [greenlet](https://github.com/python-greenlet/greenlet). +- [multiprocessing](https://docs.python.org/3/library/multiprocessing.html) - (Python standard library) Process-based parallelism. +- [trio](https://github.com/python-trio/trio) - A friendly library for async concurrency and I/O. +- [twisted](https://github.com/twisted/twisted) - An event-driven networking engine. +- [uvloop](https://github.com/MagicStack/uvloop) - Ultra fast asyncio event loop. ## Audio -*Libraries for manipulating audio and its metadata.* - -* Audio - * [audioread](https://github.com/beetbox/audioread) - Cross-library (GStreamer + Core Audio + MAD + FFmpeg) audio decoding. - * [dejavu](https://github.com/worldveil/dejavu) - Audio fingerprinting and recognition. - * [mingus](http://bspaans.github.io/python-mingus/) - An advanced music theory and notation package with MIDI file and playback support. - * [pyAudioAnalysis](https://github.com/tyiannak/pyAudioAnalysis) - Python Audio Analysis Library: Feature Extraction, Classification, Segmentation and Applications - * [pydub](https://github.com/jiaaro/pydub) - Manipulate audio with a simple and easy high level interface. - * [TimeSide](https://github.com/Parisson/TimeSide) - Open web audio processing framework. -* Metadata - * [beets](https://github.com/beetbox/beets) - A music library manager and [MusicBrainz](https://musicbrainz.org/) tagger. - * [eyeD3](https://github.com/nicfit/eyeD3) - A tool for working with audio files, specifically MP3 files containing ID3 metadata. - * [mutagen](https://github.com/quodlibet/mutagen) - A Python module to handle audio metadata. - * [tinytag](https://github.com/devsnd/tinytag) - A library for reading music meta data of MP3, OGG, FLAC and Wave files. +_Libraries for manipulating audio and its metadata._ + +- Audio + - [audioflux](https://github.com/libAudioFlux/audioFlux) - A library for audio and music analysis, feature extraction. + - [audioread](https://github.com/beetbox/audioread) - Cross-library (GStreamer + Core Audio + MAD + FFmpeg) audio decoding. + - [dejavu](https://github.com/worldveil/dejavu) - Audio fingerprinting and recognition. + - [gtts](https://github.com/pndurette/gTTS) - Python library and CLI tool for converting text to speech using Google Translate TTS. + - [kapre](https://github.com/keunwoochoi/kapre) - Keras Audio Preprocessors. + - [librosa](https://github.com/librosa/librosa) - Python library for audio and music analysis. + - [matchering](https://github.com/sergree/matchering) - A library for automated reference audio mastering. + - [mingus](https://github.com/bspaans/python-mingus) - An advanced music theory and notation package with MIDI file and playback support. + - [pyAudioAnalysis](https://github.com/tyiannak/pyAudioAnalysis) - Audio feature extraction, classification, segmentation and applications. + - [pydub](https://github.com/jiaaro/pydub) - Manipulate audio with a simple and easy high level interface. + - [TimeSide](https://github.com/Parisson/TimeSide) - Open web audio processing framework. +- Metadata + - [beets](https://github.com/beetbox/beets) - A music library manager and [MusicBrainz](https://musicbrainz.org/) tagger. + - [eyed3](https://github.com/nicfit/eyeD3) - A tool for working with audio files, specifically MP3 files containing ID3 metadata. + - [mutagen](https://github.com/quodlibet/mutagen) - A Python module to handle audio metadata. + - [tinytag](https://github.com/devsnd/tinytag) - A library for reading music meta data of MP3, OGG, FLAC and Wave files. ## Authentication -*Libraries for implementing authentications schemes.* +_Libraries for implementing authentication schemes._ -* OAuth - * [authlib](https://github.com/lepture/authlib) - JavaScript Object Signing and Encryption draft implementation. - * [django-allauth](https://github.com/pennersr/django-allauth) - Authentication app for Django that "just works." - * [django-oauth-toolkit](https://github.com/evonove/django-oauth-toolkit) - OAuth 2 goodies for Django. - * [oauthlib](https://github.com/idan/oauthlib) - A generic and thorough implementation of the OAuth request-signing logic. - * [python-oauth2](https://github.com/joestump/python-oauth2) - A fully tested, abstract interface to creating OAuth clients and servers. - * [python-social-auth](https://github.com/omab/python-social-auth) - An easy-to-setup social authentication mechanism. -* JWT - * [pyjwt](https://github.com/jpadilla/pyjwt) - JSON Web Token implementation in Python. - * [python-jose](https://github.com/mpdavis/python-jose/) - A JOSE implementation in Python. - * [python-jwt](https://github.com/davedoesdev/python-jwt) - A module for generating and verifying JSON Web Tokens. +- OAuth + - [authlib](https://github.com/lepture/authlib) - JavaScript Object Signing and Encryption draft implementation. + - [django-allauth](https://github.com/pennersr/django-allauth) - Authentication app for Django that "just works." + - [django-oauth-toolkit](https://github.com/jazzband/django-oauth-toolkit) - OAuth 2 goodies for Django. + - [oauthlib](https://github.com/oauthlib/oauthlib) - A generic and thorough implementation of the OAuth request-signing logic. +- JWT + - [pyjwt](https://github.com/jpadilla/pyjwt) - JSON Web Token implementation in Python. + - [python-jose](https://github.com/mpdavis/python-jose/) - A JOSE implementation in Python. ## Build Tools -*Compile software from source code.* +_Compile software from source code._ -* [BitBake](http://www.yoctoproject.org/docs/1.6/bitbake-user-manual/bitbake-user-manual.html) - A make-like build tool for embedded Linux. -* [buildout](http://www.buildout.org/en/latest/) - A build system for creating, assembling and deploying applications from multiple parts. -* [PlatformIO](https://github.com/platformio/platformio-core) - A console tool to build code with different development platforms. -* [pybuilder](https://github.com/pybuilder/pybuilder) - A continuous build tool written in pure Python. -* [SCons](http://www.scons.org/) - A software construction tool. +- [bitbake](https://github.com/openembedded/bitbake) - A make-like build tool for embedded Linux. +- [buildout](https://github.com/buildout/buildout) - A build system for creating, assembling and deploying applications from multiple parts. +- [platformio](https://github.com/platformio/platformio-core) - A console tool to build code with different development platforms. +- [pybuilder](https://github.com/pybuilder/pybuilder) - A continuous build tool written in pure Python. +- [scons](https://github.com/SCons/scons) - A software construction tool. ## Built-in Classes Enhancement -*Libraries for enhancing Python built-in classes.* +_Libraries for enhancing Python built-in classes._ -* [dataclasses](https://docs.python.org/3/library/dataclasses.html) - (Python standard library) Data classes. -* [attrs](https://github.com/python-attrs/attrs) - Replacement for `__init__`, `__eq__`, `__repr__`, etc. boilerplate in class definitions. -* [bidict](https://github.com/jab/bidict) - Efficient, Pythonic bidirectional map data structures and related functionality.. -* [Box](https://github.com/cdgriffith/Box) - Python dictionaries with advanced dot notation access. -* [DottedDict](https://github.com/carlosescri/DottedDict) - A library that provides a method of accessing lists and dicts with a dotted path notation. +- [attrs](https://github.com/python-attrs/attrs) - Replacement for `__init__`, `__eq__`, `__repr__`, etc. boilerplate in class definitions. +- [bidict](https://github.com/jab/bidict) - Efficient, Pythonic bidirectional map data structures and related functionality. +- [box](https://github.com/cdgriffith/Box) - Python dictionaries with advanced dot notation access. ## CMS -*Content Management Systems.* +_Content Management Systems._ -* [wagtail](https://wagtail.io/) - A Django content management system. -* [django-cms](https://www.django-cms.org/en/) - An Open source enterprise CMS based on the Django. -* [feincms](https://github.com/feincms/feincms) - One of the most advanced Content Management Systems built on Django. -* [Kotti](https://github.com/Kotti/Kotti) - A high-level, Pythonic web application framework built on Pyramid. -* [mezzanine](https://github.com/stephenmcd/mezzanine) - A powerful, consistent, and flexible content management platform. -* [plone](https://plone.org/) - A CMS built on top of the open source application server Zope. -* [quokka](https://github.com/rochacbruno/quokka) - Flexible, extensible, small CMS powered by Flask and MongoDB. +- [feincms](https://github.com/feincms/feincms) - One of the most advanced Content Management Systems built on Django. +- [indico](https://github.com/indico/indico) - A feature-rich event management system, made @ [CERN](https://en.wikipedia.org/wiki/CERN). +- [wagtail](https://github.com/wagtail/wagtail) - A Django content management system. ## Caching -*Libraries for caching data.* - -* [beaker](https://github.com/bbangert/beaker) - A WSGI middleware for sessions and caching. -* [django-cache-machine](https://github.com/django-cache-machine/django-cache-machine) - Automatic caching and invalidation for Django models. -* [django-cacheops](https://github.com/Suor/django-cacheops) - A slick ORM cache with automatic granular event-driven invalidation. -* [dogpile.cache](http://dogpilecache.readthedocs.io/en/latest/) - dogpile.cache is next generation replacement for Beaker made by same authors. -* [HermesCache](https://pypi.python.org/pypi/HermesCache) - Python caching library with tag-based invalidation and dogpile effect prevention. -* [pylibmc](https://github.com/lericson/pylibmc) - A Python wrapper around the [libmemcached](https://libmemcached.org/libMemcached.html) interface. -* [python-diskcache](http://www.grantjenks.com/docs/diskcache/) - SQLite and file backed cache backend with faster lookups than memcached and redis. - -## ChatOps Tools - -*Libraries for chatbot development.* +_Libraries for caching data._ -* [errbot](https://github.com/errbotio/errbot/) - The easiest and most popular chatbot to implement ChatOps. +- [beaker](https://github.com/bbangert/beaker) - A WSGI middleware for sessions and caching. +- [django-cache-machine](https://github.com/django-cache-machine/django-cache-machine) - Automatic caching and invalidation for Django models. +- [django-cacheops](https://github.com/Suor/django-cacheops) - A slick ORM cache with automatic granular event-driven invalidation. +- [dogpile.cache](https://github.com/sqlalchemy/dogpile.cache) - dogpile.cache is a next generation replacement for Beaker made by the same authors. +- [hermescache](https://pypi.org/project/HermesCache/) - Python caching library with tag-based invalidation and dogpile effect prevention. +- [pylibmc](https://github.com/lericson/pylibmc) - A Python wrapper around the [libmemcached](https://libmemcached.org/libMemcached.html) interface. +- [python-diskcache](https://github.com/grantjenks/python-diskcache) - SQLite and file backed cache backend with faster lookups than memcached and redis. ## Code Analysis -*Tools of static analysis, linters and code quality checkers. See: [awesome-static-analysis](https://github.com/mre/awesome-static-analysis).* - -* Code Analysis - * [coala](https://github.com/coala/coala/) - Language independent and easily extendable code analysis application. - * [code2flow](https://github.com/scottrogowski/code2flow) - Turn your Python and JavaScript code into DOT flowcharts. - * [prospector](https://github.com/PyCQA/prospector) - A tool to analyse Python code. - * [pycallgraph](https://github.com/gak/pycallgraph) - A library that visualises the flow (call graph) of your Python application. -* Code Linters - * [flake8](https://pypi.python.org/pypi/flake8) - A wrapper around `pycodestyle`, `pyflakes` and McCabe. - * [pylint](https://www.pylint.org/) - A fully customizable source code analyzer. - * [pylama](https://github.com/klen/pylama) - A code audit tool for Python and JavaScript. -Code Formatters - * [black](https://github.com/ambv/black) - The uncompromising Python code formatter. - * [yapf](https://github.com/google/yapf) - Yet another Python code formatter from Google. -* Static Type Checkers - * [mypy](http://mypy-lang.org/) - Check variable types during compile time. - * [pyre-check](https://github.com/facebook/pyre-check) - Performant type checking. -* Static Type Annotations Generators - * [MonkeyType](https://github.com/Instagram/MonkeyType) - A system for Python that generates static type annotations by collecting runtime types +_Tools of static analysis, linters and code quality checkers. Also see [awesome-static-analysis](https://github.com/mre/awesome-static-analysis)._ + +- Code Analysis + - [code-graph-rag](https://github.com/vitali87/code-graph-rag) - Builds knowledge graphs from multi-language codebases using Tree-sitter and Memgraph, enabling natural language querying of code structure. + - [code2flow](https://github.com/scottrogowski/code2flow) - Turn your Python and JavaScript code into DOT flowcharts. + - [prospector](https://github.com/PyCQA/prospector) - A tool to analyze Python code. + - [vulture](https://github.com/jendrikseipp/vulture) - A tool for finding and analyzing dead Python code. +- Code Linters + - [flake8](https://github.com/PyCQA/flake8) - A wrapper around `pycodestyle`, `pyflakes` and McCabe. + - [awesome-flake8-extensions](https://github.com/DmytroLitvinov/awesome-flake8-extensions) + - [pylint](https://github.com/pylint-dev/pylint) - A fully customizable source code analyzer. + - [ruff](https://github.com/astral-sh/ruff) - An extremely fast Python linter and code formatter. +- Code Formatters + - [black](https://github.com/psf/black) - The uncompromising Python code formatter. + - [isort](https://github.com/timothycrosley/isort) - A Python utility / library to sort imports. + - [yapf](https://github.com/google/yapf) - Yet another Python code formatter from Google. +- Static Type Checkers, also see [awesome-python-typing](https://github.com/typeddjango/awesome-python-typing) + - [mypy](https://github.com/python/mypy) - Check variable types during compile time. + - [pyre-check](https://github.com/facebook/pyre-check) - Performant type checking. + - [ty](https://github.com/astral-sh/ty) - An extremely fast Python type checker and language server. + - [typeshed](https://github.com/python/typeshed) - Collection of library stubs for Python, with static types. +- Static Type Annotations Generators + - [monkeytype](https://github.com/Instagram/MonkeyType) - A system for Python that generates static type annotations by collecting runtime types. + - [pytype](https://github.com/google/pytype) - Pytype checks and infers types for Python code - without requiring type annotations. + +## Command-line Interface Development + +_Libraries for building command-line applications._ + +- Command-line Application Development + - [argparse](https://docs.python.org/3/library/argparse.html) - (Python standard library) Command-line option and argument parsing. + - [cement](https://github.com/datafolklabs/cement) - CLI Application Framework for Python. + - [click](https://github.com/pallets/click/) - A package for creating beautiful command line interfaces in a composable way. + - [cliff](https://github.com/openstack/cliff) - A framework for creating command-line programs with multi-level commands. + - [python-fire](https://github.com/google/python-fire) - A library for creating command line interfaces from absolutely any Python object. + - [python-prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) - A library for building powerful interactive command lines. + - [typer](https://github.com/tiangolo/typer) - Modern CLI framework that uses Python type hints. Built on Click and Pydantic. +- Terminal Rendering + - [alive-progress](https://github.com/rsalmei/alive-progress) - A new kind of Progress Bar, with real-time throughput, eta and very cool animations. + - [asciimatics](https://github.com/peterbrittain/asciimatics) - A package to create full-screen text UIs (from interactive forms to ASCII animations). + - [bashplotlib](https://github.com/glamp/bashplotlib) - Making basic plots in the terminal. + - [colorama](https://github.com/tartley/colorama) - Cross-platform colored terminal text. + - [rich](https://github.com/Textualize/rich) - Python library for rich text and beautiful formatting in the terminal. Also provides a great `RichHandler` log handler. + - [textual](https://github.com/Textualize/textual) - A framework for building interactive user interfaces that run in the terminal and the browser. + - [tqdm](https://github.com/tqdm/tqdm) - Fast, extensible progress bar for loops and CLI. ## Command-line Tools -*Libraries for building command-line application.* - -* Command-line Application Development - * [cement](http://builtoncement.com/) - CLI Application Framework for Python. - * [click](http://click.pocoo.org/dev/) - A package for creating beautiful command line interfaces in a composable way. - * [cliff](https://docs.openstack.org/developer/cliff/) - A framework for creating command-line programs with multi-level commands. - * [clint](https://github.com/kennethreitz/clint) - Python Command-line Application Tools. - * [docopt](http://docopt.org/) - Pythonic command line arguments parser. - * [python-fire](https://github.com/google/python-fire) - A library for creating command line interfaces from absolutely any Python object. - * [python-prompt-toolkit](https://github.com/jonathanslenders/python-prompt-toolkit) - A library for building powerful interactive command lines. -* Terminal Rendering - * [asciimatics](https://github.com/peterbrittain/asciimatics) - A package to create full-screen text UIs (from interactive forms to ASCII animations). - * [bashplotlib](https://github.com/glamp/bashplotlib) - Making basic plots in the terminal. - * [colorama](https://pypi.python.org/pypi/colorama) - Cross-platform colored terminal text. -* Productivity Tools - * [cookiecutter](https://github.com/audreyr/cookiecutter) - A command-line utility that creates projects from cookiecutters (project templates). - * [doitlive](https://github.com/sloria/doitlive) - A tool for live presentations in the terminal. - * [howdoi](https://github.com/gleitz/howdoi) - Instant coding answers via the command line. - * [PathPicker](https://github.com/facebook/PathPicker) - Select files out of bash output. - * [percol](https://github.com/mooz/percol) - Adds flavor of interactive selection to the traditional pipe concept on UNIX. - * [thefuck](https://github.com/nvbn/thefuck) - Correcting your previous console command. - * [tmuxp](https://github.com/tony/tmuxp) - A [tmux](https://github.com/tmux/tmux) session manager. - * [try](https://github.com/timofurrer/try) - A dead simple CLI to try out python packages - it's never been easier. -* CLI Enhancements - * [httpie](https://github.com/jakubroztocil/httpie) - A command line HTTP client, a user-friendly cURL replacement. - * [kube-shell](https://github.com/cloudnativelabs/kube-shell) - An integrated shell for working with the Kubernetes CLI. - * [mycli](https://github.com/dbcli/mycli) - A Terminal Client for MySQL with AutoCompletion and Syntax Highlighting. - * [pgcli](https://github.com/dbcli/pgcli) - Postgres CLI with autocompletion and syntax highlighting. - * [saws](https://github.com/donnemartin/saws) - A Supercharged [aws-cli](https://github.com/aws/aws-cli). - -## Compatibility - -*Libraries for migrating from Python 2 to 3.* - -* [python-future](http://python-future.org/index.html) - The missing compatibility layer between Python 2 and Python 3. -* [python-modernize](https://github.com/mitsuhiko/python-modernize) - Modernizes Python code for eventual Python 3 migration. -* [six](https://pypi.python.org/pypi/six) - Python 2 and 3 compatibility utilities. +_Useful CLI-based tools for productivity._ + +- Productivity Tools + - [ccb](https://github.com/bfly123/claude_code_bridge) - A CLI tool to orchestrate multiple LLMs (Claude, Gemini, etc.) in Tmux panes with cross-agent interaction. + - [cookiecutter](https://github.com/cookiecutter/cookiecutter) - A command-line utility that creates projects from cookiecutters (project templates). + - [copier](https://github.com/copier-org/copier) - A library and command-line utility for rendering projects templates. + - [doitlive](https://github.com/sloria/doitlive) - A tool for live presentations in the terminal. + - [howdoi](https://github.com/gleitz/howdoi) - Instant coding answers via the command line. + - [invoke](https://github.com/pyinvoke/invoke) - A tool for managing shell-oriented subprocesses and organizing executable Python code into CLI-invokable tasks. + - [fpp](https://github.com/facebook/PathPicker) - Select files out of bash output. + - [thefuck](https://github.com/nvbn/thefuck) - Correcting your previous console command. + - [tmuxp](https://github.com/tmux-python/tmuxp) - A [tmux](https://github.com/tmux/tmux) session manager. + - [try](https://github.com/timofurrer/try) - A dead simple CLI to try out python packages - it's never been easier. +- CLI Enhancements + - [httpie](https://github.com/httpie/cli) - A command line HTTP client, a user-friendly cURL replacement. + - [iredis](https://github.com/laixintao/iredis) - Redis CLI with autocompletion and syntax highlighting. + - [litecli](https://github.com/dbcli/litecli) - SQLite CLI with autocompletion and syntax highlighting. + - [mycli](https://github.com/dbcli/mycli) - MySQL CLI with autocompletion and syntax highlighting. + - [pgcli](https://github.com/dbcli/pgcli) - PostgreSQL CLI with autocompletion and syntax highlighting. ## Computer Vision -*Libraries for computer vision.* - -* [OpenCV](https://opencv.org/) - Open Source Computer Vision Library. -* [pytesseract](https://github.com/madmaze/pytesseract) - Another wrapper for [Google Tesseract OCR](https://github.com/tesseract-ocr). -* [SimpleCV](http://simplecv.org/) - An open source framework for building computer vision applications. - -## Concurrency and Parallelism - -*Libraries for concurrent and parallel execution. See [awesome-asyncio](https://github.com/timofurrer/awesome-asyncio).* +_Libraries for Computer Vision._ -* [concurrent.futures](https://docs.python.org/3/library/concurrent.futures.html) - (Python standard library) A high-level interface for asynchronously executing callables. -* [multiprocessing](https://docs.python.org/3/library/multiprocessing.html) - (Python standard library) Process-based parallelism. -* [eventlet](http://eventlet.net/) - Asynchronous framework with WSGI support. -* [gevent](http://www.gevent.org/) - A coroutine-based Python networking library that uses [greenlet](https://github.com/python-greenlet/greenlet). -* [uvloop](https://github.com/MagicStack/uvloop) - Ultra fast implementation of `asyncio` event loop on top of `libuv`. -* [scoop](https://github.com/soravux/scoop) - Scalable Concurrent Operations in Python. +- [easyocr](https://github.com/JaidedAI/EasyOCR) - Ready-to-use OCR with 40+ languages supported. +- [kornia](https://github.com/kornia/kornia/) - Open Source Differentiable Computer Vision Library for PyTorch. +- [opencv](https://github.com/opencv/opencv-python) - Open Source Computer Vision Library. +- [pytesseract](https://github.com/madmaze/pytesseract) - A wrapper for [Google Tesseract OCR](https://github.com/tesseract-ocr). +- [tesserocr](https://github.com/sirfz/tesserocr) - Another simple, Pillow-friendly, wrapper around the `tesseract-ocr` API for OCR. -## Configuration +## Configuration Files -*Libraries for storing and parsing configuration options.* +_Libraries for storing and parsing configuration options._ -* [configobj](https://github.com/DiffSK/configobj) - INI file parser with validation. -* [configparser](https://docs.python.org/3/library/configparser.html) - (Python standard library) INI file parser. -* [profig](https://profig.readthedocs.io/en/default/) - Config from multiple formats with value conversion. -* [python-decouple](https://github.com/henriquebastos/python-decouple) - Strict separation of settings from code. +- [configobj](https://github.com/DiffSK/configobj) - INI file parser with validation. +- [configparser](https://docs.python.org/3/library/configparser.html) - (Python standard library) INI file parser. +- [dynaconf](https://github.com/dynaconf/dynaconf) - Dynaconf is a configuration manager with plugins for Django, Flask and FastAPI. +- [hydra](https://github.com/facebookresearch/hydra) - Hydra is a framework for elegantly configuring complex applications. +- [python-decouple](https://github.com/HBNetwork/python-decouple) - Strict separation of settings from code. ## Cryptography -* [cryptography](https://cryptography.io/en/latest/) - A package designed to expose cryptographic primitives and recipes to Python developers. -* [paramiko](https://github.com/paramiko/paramiko) - A Python (2.6+, 3.3+) implementation of the SSHv2 protocol, providing both client and server functionality. -* [passlib](https://passlib.readthedocs.io/en/stable/) - Secure password storage/hashing library, very high level. -* [pynacl](https://github.com/pyca/pynacl) - Python binding to the Networking and Cryptography (NaCl) library. +- [cryptography](https://github.com/pyca/cryptography) - A package designed to expose cryptographic primitives and recipes to Python developers. +- [paramiko](https://github.com/paramiko/paramiko) - The leading native Python SSHv2 protocol library. +- [pynacl](https://github.com/pyca/pynacl) - Python binding to the Networking and Cryptography (NaCl) library. ## Data Analysis -*Libraries for data analyzing.* +_Libraries for data analysis._ -* [Blaze](https://github.com/blaze/blaze) - NumPy and Pandas interface to Big Data. -* [Open Mining](https://github.com/mining/mining) - Business Intelligence (BI) in Pandas interface. -* [Orange](https://orange.biolab.si/) - Data mining, data visualization, analysis and machine learning through visual programming or scripts. -* [Pandas](http://pandas.pydata.org/) - A library providing high-performance, easy-to-use data structures and data analysis tools. -* [Optimus](https://github.com/ironmussa/Optimus) - Cleansing, pre-processing, feature engineering, exploratory data analysis and easy Machine Learning with a PySpark backend. +- [aws-sdk-pandas](https://github.com/aws/aws-sdk-pandas) - Pandas on AWS. +- [datasette](https://github.com/simonw/datasette) - An open source multi-tool for exploring and publishing data. +- [desbordante](https://github.com/desbordante/desbordante-core/) - An open source data profiler for complex pattern discovery. +- [optimus](https://github.com/hi-primus/optimus) - Agile Data Science Workflows made easy with PySpark. +- [pandas](https://github.com/pandas-dev/pandas) - A library providing high-performance, easy-to-use data structures and data analysis tools. +- [pathway](https://github.com/pathwaycom/pathway) - Real-time data processing framework for Python with reactive dataflows. +- [polars](https://github.com/pola-rs/polars) - A fast DataFrame library implemented in Rust with a Python API. ## Data Validation -*Libraries for validating data. Used for forms in many cases.* +_Libraries for validating data. Used for forms in many cases._ -* [Cerberus](https://github.com/pyeve/cerberus) - A lightweight and extensible data validation library. -* [colander](https://docs.pylonsproject.org/projects/colander/en/latest/) - Validating and deserializing data obtained via XML, JSON, an HTML form post. -* [Dash](https://plot.ly/products/dash/) - Built on top of Flask, React and Plotly aimed at analytical web applications. - * [awesome-dash](https://github.com/Acrotrend/awesome-dash) -* [jsonschema](https://github.com/Julian/jsonschema) - An implementation of [JSON Schema](http://json-schema.org/) for Python. -* [schema](https://github.com/keleshev/schema) - A library for validating Python data structures. -* [Schematics](https://github.com/schematics/schematics) - Data Structure Validation. -* [valideer](https://github.com/podio/valideer) - Lightweight extensible data validation and adaptation library. -* [voluptuous](https://github.com/alecthomas/voluptuous) - A Python data validation library. +- [cerberus](https://github.com/pyeve/cerberus) - A lightweight and extensible data validation library. +- [colander](https://github.com/Pylons/colander) - Validating and deserializing data obtained via XML, JSON, an HTML form post. +- [jsonschema](https://github.com/python-jsonschema/jsonschema) - An implementation of [JSON Schema](http://json-schema.org/) for Python. +- [pydantic](https://github.com/pydantic/pydantic) - Data validation using Python type hints. +- [schema](https://github.com/keleshev/schema) - A library for validating Python data structures. +- [schematics](https://github.com/schematics/schematics) - Data Structure Validation. +- [voluptuous](https://github.com/alecthomas/voluptuous) - A Python data validation library. ## Data Visualization -*Libraries for visualizing data. See: [awesome-javascript](https://github.com/sorrycc/awesome-javascript#data-visualization).* - -* [Altair](https://github.com/altair-viz/altair) - Declarative statistical visualization library for Python. -* [Bokeh](https://github.com/bokeh/bokeh) - Interactive Web Plotting for Python. -* [bqplot](https://github.com/bloomberg/bqplot) - Interactive Plotting Library for the Jupyter Notebook -* [ggplot](https://github.com/yhat/ggpy) - Same API as ggplot2 for R. -* [Matplotlib](http://matplotlib.org/) - A Python 2D plotting library. -* [Pygal](http://www.pygal.org/en/latest/) - A Python SVG Charts Creator. -* [PyGraphviz](https://pypi.python.org/pypi/pygraphviz) - Python interface to [Graphviz](http://www.graphviz.org/). -* [PyQtGraph](http://www.pyqtgraph.org/) - Interactive and realtime 2D/3D/Image plotting and science/engineering widgets. -* [Seaborn](https://github.com/mwaskom/seaborn) - Statistical data visualization using Matplotlib. -* [VisPy](https://github.com/vispy/vispy) - High-performance scientific visualization based on OpenGL. +_Libraries for visualizing data. Also see [awesome-javascript](https://github.com/sorrycc/awesome-javascript#data-visualization)._ + +- [altair](https://github.com/altair-viz/altair) - Declarative statistical visualization library for Python. +- [bokeh](https://github.com/bokeh/bokeh) - Interactive Web Plotting for Python. +- [bqplot](https://github.com/bloomberg/bqplot) - Interactive Plotting Library for the Jupyter Notebook. +- [cartopy](https://github.com/SciTools/cartopy) - A cartographic python library with matplotlib support. +- [diagrams](https://github.com/mingrammer/diagrams) - Diagram as Code. +- [matplotlib](https://github.com/matplotlib/matplotlib) - A Python 2D plotting library. +- [plotly](https://github.com/plotly/plotly.py) - Interactive graphing library for Python. +- [plotnine](https://github.com/has2k1/plotnine) - A grammar of graphics for Python based on ggplot2. +- [pygal](https://github.com/Kozea/pygal) - A Python SVG Charts Creator. +- [pygraphviz](https://github.com/pygraphviz/pygraphviz/) - Python interface to [Graphviz](http://www.graphviz.org/). +- [pyqtgraph](https://github.com/pyqtgraph/pyqtgraph) - Interactive and realtime 2D/3D/Image plotting and science/engineering widgets. +- [seaborn](https://github.com/mwaskom/seaborn) - Statistical data visualization using Matplotlib. +- [streamlit](https://github.com/streamlit/streamlit) - A framework which lets you build dashboards, generate reports, or create chat apps in minutes. +- [ultraplot](https://github.com/ultraplot/UltraPlot) - Matplotlib wrapper for publication-ready scientific figures with minimal code. Includes advanced subplot management, panel layouts, and batteries-included geoscience plotting. +- [vispy](https://github.com/vispy/vispy) - High-performance scientific visualization based on OpenGL. ## Database -*Databases implemented in Python.* +_Databases implemented in Python._ -* [pickleDB](https://github.com/patx/pickledb) - A simple and lightweight key-value store for Python. -* [tinydb](https://github.com/msiemens/tinydb) - A tiny, document-oriented database. -* [ZODB](https://github.com/zopefoundation/ZODB) - A native object database for Python. A key-value and object graph database. +- [duckdb](https://github.com/duckdb/duckdb) - An in-process SQL OLAP database management system; optimized for analytics and fast queries, similar to SQLite but for analytical workloads. +- [pickledb](https://github.com/patx/pickledb) - A simple and lightweight key-value store for Python. +- [tinydb](https://github.com/msiemens/tinydb) - A tiny, document-oriented database. +- [ZODB](https://github.com/zopefoundation/ZODB) - A native object database for Python. A key-value and object graph database. ## Database Drivers -*Libraries for connecting and operating databases.* - -* MySQL - [awesome-mysql](http://shlomi-noach.github.io/awesome-mysql/) - * [mysqlclient](https://github.com/PyMySQL/mysqlclient-python) - MySQL connector with Python 3 support ([mysql-python](https://sourceforge.net/projects/mysql-python/) fork). - * [PyMySQL](https://github.com/PyMySQL/PyMySQL) - A pure Python MySQL driver compatible to mysql-python. -* PostgreSQL - [awesome-postgres](https://github.com/dhamaniasad/awesome-postgres) - * [psycopg2](http://initd.org/psycopg/) - The most popular PostgreSQL adapter for Python. - * [queries](https://github.com/gmr/queries) - A wrapper of the psycopg2 library for interacting with PostgreSQL. -* Other Relational Databases - * [pymssql](http://www.pymssql.org/en/latest/) - A simple database interface to Microsoft SQL Server. -* NoSQL Databases - * [cassandra-driver](https://github.com/datastax/python-driver) - The Python Driver for Apache Cassandra. - * [happybase](https://github.com/wbolster/happybase) - A developer-friendly library for Apache HBase. - * [kafka-python](https://github.com/dpkp/kafka-python) - The Python client for Apache Kafka. - * [py2neo](https://py2neo.org/) - Python wrapper client for Neo4j's restful interface. - * [pymongo](https://github.com/mongodb/mongo-python-driver) - The official Python client for MongoDB. - * [redis-py](https://github.com/andymccurdy/redis-py) - The Python client for Redis. -* Asynchronous Clients - * [motor](https://github.com/mongodb/motor) - The async Python driver for MongoDB. - * [Telephus](https://github.com/driftx/Telephus) - Twisted based client for Cassandra. - * [txpostgres](https://github.com/wulczer/txpostgres) - Twisted based asynchronous driver for PostgreSQL. - * [txRedis](https://github.com/deldotdr/txRedis) - Twisted based client for Redis. +_Libraries for connecting and operating databases._ + +- MySQL - [awesome-mysql](https://github.com/shlomi-noach/awesome-mysql) + - [mysqlclient](https://github.com/PyMySQL/mysqlclient) - MySQL connector with Python 3 support ([mysql-python](https://sourceforge.net/projects/mysql-python/) fork). + - [pymysql](https://github.com/PyMySQL/PyMySQL) - A pure Python MySQL driver compatible to mysql-python. +- PostgreSQL - [awesome-postgres](https://github.com/dhamaniasad/awesome-postgres) + - [psycopg](https://github.com/psycopg/psycopg) - The most popular PostgreSQL adapter for Python. +- SQlite - [awesome-sqlite](https://github.com/planetopendata/awesome-sqlite) + - [sqlite-utils](https://github.com/simonw/sqlite-utils) - Python CLI utility and library for manipulating SQLite databases. + - [sqlite3](https://docs.python.org/3/library/sqlite3.html) - (Python standard library) SQlite interface compliant with DB-API 2.0. +- Other Relational Databases + - [clickhouse-driver](https://github.com/mymarilyn/clickhouse-driver) - Python driver with native interface for ClickHouse. + - [pymssql](https://github.com/pymssql/pymssql) - A simple database interface to Microsoft SQL Server. +- NoSQL Databases + - [cassandra-driver](https://github.com/datastax/python-driver) - The Python Driver for Apache Cassandra. + - [django-mongodb-backend](https://github.com/mongodb/django-mongodb-backend) - Official MongoDB database backend for Django. + - [kafka-python](https://github.com/dpkp/kafka-python) - The Python client for Apache Kafka. + - [pymongo](https://github.com/mongodb/mongo-python-driver) - The official Python client for MongoDB. + - [redis-py](https://github.com/redis/redis-py) - The Python client for Redis. ## Date and Time -*Libraries for working with dates and times.* +_Libraries for working with dates and times._ -* [Chronyk](https://github.com/KoffeinFlummi/Chronyk) - A Python 3 library for parsing human-written times and dates. -* [dateutil](https://github.com/dateutil/dateutil) - Extensions to the standard Python [datetime](https://docs.python.org/3/library/datetime.html) module. -* [delorean](https://github.com/myusuf3/delorean/) - A library for clearing up the inconvenient truths that arise dealing with datetimes. -* [moment](https://github.com/zachwill/moment) - A Python library for dealing with dates/times. Inspired by [Moment.js](http://momentjs.com/). -* [Pendulum](https://github.com/sdispater/pendulum) - Python datetimes made easy. -* [PyTime](https://github.com/shinux/PyTime) - A easy-use Python module which aims to operate date/time/datetime by string. -* [pytz](https://launchpad.net/pytz) - World timezone definitions, modern and historical. Brings the [tz database](https://en.wikipedia.org/wiki/Tz_database) into Python. -* [when.py](https://github.com/dirn/When.py) - Providing user-friendly functions to help perform common date and time actions. -* [maya](https://github.com/kennethreitz/maya) - Datetimes for Humans, Maya is mostly built around the headaches and use-cases around parsing datetime data from websites. +- [arrow](https://github.com/arrow-py/arrow) - A Python library that offers a sensible and human-friendly approach to creating, manipulating, formatting and converting dates, times and timestamps. +- [dateutil](https://github.com/dateutil/dateutil) - Extensions to the standard Python [datetime](https://docs.python.org/3/library/datetime.html) module. +- [pendulum](https://github.com/sdispater/pendulum) - Python datetimes made easy. +- [zoneinfo](https://docs.python.org/3/library/zoneinfo.html) - (Python standard library) IANA time zone support. Brings the [tz database](https://en.wikipedia.org/wiki/Tz_database) into Python. ## Debugging Tools -*Libraries for debugging code.* - -* pdb-like Debugger - * [ipdb](https://github.com/gotcha/ipdb) - IPython-enabled [pdb](https://docs.python.org/3/library/pdb.html). - * [pdb++](https://github.com/antocuni/pdb) - Another drop-in replacement for pdb. - * [pudb](https://github.com/inducer/pudb) - A full-screen, console-based Python debugger. - * [wdb](https://github.com/Kozea/wdb) - An improbable web debugger through WebSockets. -* Tracing - * [lptrace](https://github.com/khamidou/lptrace) - [strace](http://man7.org/linux/man-pages/man1/strace.1.html) for Python programs. - * [manhole](https://github.com/ionelmc/python-manhole) - Debug service that will accept unix domain socket connections and present the stacktraces for all threads and an interactive prompt. - * [pyringe](https://github.com/google/pyringe) - Debugger capable of attaching to and injecting code into Python processes. - * [python-hunter](https://github.com/ionelmc/python-hunter) - A flexible code tracing toolkit. -* Profiler - * [line_profiler](https://github.com/rkern/line_profiler) - Line-by-line profiling. - * [memory_profiler](https://github.com/fabianp/memory_profiler) - Monitor Memory usage of Python code. - * [profiling](https://github.com/what-studio/profiling) - An interactive Python profiler. - * [py-spy](https://github.com/benfred/py-spy) - A sampling profiler for Python programs. Written in Rust. - * [pyflame](https://github.com/uber/pyflame) - A ptracing profiler For Python. - * [vprof](https://github.com/nvdv/vprof) - Visual Python profiler. -* Others - * [icecream](https://github.com/gruns/icecream) - Inspect variables, expressions, and program execution with a single, simple function call. - * [django-debug-toolbar](https://github.com/jazzband/django-debug-toolbar) - Display various debug information for Django. - * [django-devserver](https://github.com/dcramer/django-devserver) - A drop-in replacement for Django's runserver. - * [flask-debugtoolbar](https://github.com/mgood/flask-debugtoolbar) - A port of the django-debug-toolbar to flask. - * [pyelftools](https://github.com/eliben/pyelftools) - Parsing and analyzing ELF files and DWARF debugging information. +_Libraries for debugging code._ + +- pdb-like Debugger + - [ipdb](https://github.com/gotcha/ipdb) - IPython-enabled [pdb](https://docs.python.org/3/library/pdb.html). + - [pudb](https://github.com/inducer/pudb) - A full-screen, console-based Python debugger. +- Tracing + - [manhole](https://github.com/ionelmc/python-manhole) - Debugging UNIX socket connections and present the stacktraces for all threads and an interactive prompt. + - [python-hunter](https://github.com/ionelmc/python-hunter) - A flexible code tracing toolkit. +- Profiler + - [py-spy](https://github.com/benfred/py-spy) - A sampling profiler for Python programs. Written in Rust. + - [vprof](https://github.com/nvdv/vprof) - Visual Python profiler. +- Others + - [django-debug-toolbar](https://github.com/jazzband/django-debug-toolbar) - Display various debug information for Django. + - [flask-debugtoolbar](https://github.com/pallets-eco/flask-debugtoolbar) - A port of the django-debug-toolbar to flask. + - [icecream](https://github.com/gruns/icecream) - Inspect variables, expressions, and program execution with a single, simple function call. + - [memory_graph](https://github.com/bterwijn/memory_graph) - Visualize Python data at runtime to debug references, mutability, and aliasing. + - [pyelftools](https://github.com/eliben/pyelftools) - Parsing and analyzing ELF files and DWARF debugging information. ## Deep Learning -*Frameworks for Neural Networks and Deep Learning. See: [awesome-deep-learning](https://github.com/ChristosChristofidis/awesome-deep-learning).* +_Frameworks for Neural Networks and Deep Learning. Also see [awesome-deep-learning](https://github.com/ChristosChristofidis/awesome-deep-learning)._ -* [caffe](https://github.com/BVLC/caffe) - A fast open framework for deep learning.. -* [keras](https://github.com/keras-team/keras) - A high-level neural networks library and capable of running on top of either TensorFlow or Theano. -* [mxnet](https://github.com/dmlc/mxnet) - A deep learning framework designed for both efficiency and flexibility. -* [pytorch](https://github.com/pytorch/pytorch) - Tensors and Dynamic neural networks in Python with strong GPU acceleration. -* [SerpentAI](https://github.com/SerpentAI/SerpentAI) - Game agent framework. Use any video game as a deep learning sandbox. -* [tensorflow](https://github.com/tensorflow/tensorflow) - The most popular Deep Learning framework created by Google. -* [Theano](https://github.com/Theano/Theano) - A library for fast numerical computation. +- [jax](https://github.com/google/jax) - a library for high-performance numerical computing with automatic differentiation and JIT compilation. +- [keras](https://github.com/keras-team/keras) - A high-level neural networks library and capable of running on top of either TensorFlow or Theano. +- [pytorch-lightning](https://github.com/Lightning-AI/pytorch-lightning) - Deep learning framework to train, deploy, and ship AI products Lightning fast. +- [pytorch](https://github.com/pytorch/pytorch) - Tensors and Dynamic neural networks in Python with strong GPU acceleration. +- [stable-baselines3](https://github.com/DLR-RM/stable-baselines3) - PyTorch implementations of Stable Baselines (deep) reinforcement learning algorithms. +- [tensorflow](https://github.com/tensorflow/tensorflow) - The most popular Deep Learning framework created by Google. +- [vllm](https://github.com/vllm-project/vllm) - A high-throughput and memory-efficient inference and serving engine for LLMs. ## DevOps Tools -*Software and libraries for DevOps.* - -* [ansible](https://github.com/ansible/ansible) - A radically simple IT automation platform. -* [cloudinit](https://cloudinit.readthedocs.io/en/latest/) - A multi-distribution package that handles early initialization of a cloud instance. -* [cuisine](https://github.com/sebastien/cuisine) - Chef-like functionality for Fabric. -* [docker-compose](https://docs.docker.com/compose/) - Fast, isolated development environments using [Docker](https://www.docker.com/). -* [fabric](https://github.com/fabric/fabric) - A simple, Pythonic tool for remote execution and deployment. -* [fabtools](https://github.com/fabtools/fabtools) - Tools for writing awesome Fabric files. -* [honcho](https://github.com/nickstenning/honcho) - A Python clone of [Foreman](https://github.com/ddollar/foreman), for managing Procfile-based applications. -* [OpenStack](https://www.openstack.org/) - Open source software for building private and public clouds. -* [pexpect](https://github.com/pexpect/pexpect) - Controlling interactive programs in a pseudo-terminal like GNU expect. -* [psutil](https://github.com/giampaolo/psutil) - A cross-platform process and system utilities module. -* [saltstack](https://github.com/saltstack/salt) - Infrastructure automation and management system. -* [supervisor](https://github.com/Supervisor/supervisor) - Supervisor process control system for UNIX. +_Software and libraries for DevOps._ + +- Cloud Providers + - [boto3](https://github.com/boto/boto3) - Python interface to Amazon Web Services. +- Configuration Management + - [ansible](https://github.com/ansible/ansible) - A radically simple IT automation platform. + - [cloudinit](https://github.com/canonical/cloud-init) - A multi-distribution package that handles early initialization of a cloud instance. + - [openstack](https://www.openstack.org/) - Open source software for building private and public clouds. + - [pyinfra](https://github.com/pyinfra-dev/pyinfra) - A versatile CLI tools and python libraries to automate infrastructure. + - [saltstack](https://github.com/saltstack/salt) - Infrastructure automation and management system. +- SSH-style Deployment + - [cuisine](https://github.com/sebastien/cuisine) - Chef-like functionality for Fabric. + - [fabric](https://github.com/fabric/fabric) - A simple, Pythonic tool for remote execution and deployment. +- Process Management + - [supervisor](https://github.com/Supervisor/supervisor) - Supervisor process control system for UNIX. +- Monitoring + - [psutil](https://github.com/giampaolo/psutil) - A cross-platform process and system utilities module. +- Backup + - [borg](https://github.com/borgbackup/borg) - A deduplicating archiver with compression and encryption. +- Chaos Engineering + - [chaostoolkit](https://github.com/chaostoolkit/chaostoolkit) - A Chaos Engineering toolkit & Orchestration for Developers. ## Distributed Computing -*Frameworks and libraries for Distributed Computing.* +_Frameworks and libraries for Distributed Computing._ -* Batch Processing - * [PySpark](https://pypi.python.org/pypi/pyspark/) - [Apache Spark](https://spark.apache.org/) Python API. - * [dask](https://github.com/dask/dask) - A flexible parallel computing library for analytic computing. - * [luigi](https://github.com/spotify/luigi) - A module that helps you build complex pipelines of batch jobs. - * [mrjob](https://github.com/Yelp/mrjob) - Run MapReduce jobs on Hadoop or Amazon Web Services. - * [Ray](https://github.com/ray-project/ray/) - A system for parallel and distributed Python that unifies the machine learning ecosystem. -* Stream Processing - * [faust](https://github.com/robinhood/faust) - A stream processing library, porting the ideas from [Kafka Streams](https://kafka.apache.org/documentation/streams/) to Python. - * [streamparse](https://github.com/Parsely/streamparse) - Run Python code against real-time streams of data via [Apache Storm](http://storm.apache.org/). +- Batch Processing + - [dask](https://github.com/dask/dask) - A flexible parallel computing library for analytic computing. + - [luigi](https://github.com/spotify/luigi) - A module that helps you build complex pipelines of batch jobs. + - [mpi4py](https://github.com/mpi4py/mpi4py) - Python bindings for MPI. + - [pyspark](https://github.com/apache/spark) - [Apache Spark](https://spark.apache.org/) Python API. + - [ray](https://github.com/ray-project/ray/) - A system for parallel and distributed Python that unifies the machine learning ecosystem. +- Stream Processing + - [streamparse](https://github.com/Parsely/streamparse) - Run Python code against real-time streams of data via [Apache Storm](http://storm.apache.org/). ## Distribution -*Libraries to create packaged executables for release distribution.* +_Libraries to create packaged executables for release distribution._ -* [dh-virtualenv](https://github.com/spotify/dh-virtualenv) - Build and distribute a virtualenv as a Debian package. -* [Nuitka](http://nuitka.net/) - Compile scripts, modules, packages to an executable or extension module. -* [py2app](http://pythonhosted.org/py2app/) - Freezes Python scripts (Mac OS X). -* [py2exe](http://www.py2exe.org/) - Freezes Python scripts (Windows). -* [PyInstaller](https://github.com/pyinstaller/pyinstaller) - Converts Python programs into stand-alone executables (cross-platform). -* [pynsist](http://pynsist.readthedocs.io/en/latest/) - A tool to build Windows installers, installers bundle Python itself. +- [cx-Freeze](https://github.com/marcelotduarte/cx_Freeze) - It is a Python tool that converts Python scripts into standalone executables and installers for Windows, macOS, and Linux. +- [Nuitka](https://github.com/Nuitka/Nuitka) - Compiles Python programs into high-performance standalone executables (cross-platform, supports all Python versions). +- [py2app](https://github.com/ronaldoussoren/py2app) - Freezes Python scripts (Mac OS X). +- [py2exe](https://github.com/py2exe/py2exe) - Freezes Python scripts (Windows). +- [pyarmor](https://github.com/dashingsoft/pyarmor) - A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts. +- [pyinstaller](https://github.com/pyinstaller/pyinstaller) - Converts Python programs into stand-alone executables (cross-platform). +- [shiv](https://github.com/linkedin/shiv) - A command line utility for building fully self-contained zipapps (PEP 441), but with all their dependencies included. ## Documentation -*Libraries for generating project documentation.* +_Libraries for generating project documentation._ -* [sphinx](https://github.com/sphinx-doc/sphinx/) - Python Documentation generator. - * [awesome-sphinxdoc](https://github.com/yoloseem/awesome-sphinxdoc) -* [pdoc](https://github.com/mitmproxy/pdoc) - Epydoc replacement to auto generate API documentation for Python libraries. -* [pycco](https://github.com/pycco-docs/pycco) - The literate-programming-style documentation generator. +- [sphinx](https://github.com/sphinx-doc/sphinx/) - Python Documentation generator. + - [awesome-sphinxdoc](https://github.com/yoloseem/awesome-sphinxdoc) +- [pdoc](https://github.com/mitmproxy/pdoc) - Epydoc replacement to auto generate API documentation for Python libraries. ## Downloader -*Libraries for downloading.* - -* [s3cmd](https://github.com/s3tools/s3cmd) - A command line tool for managing Amazon S3 and CloudFront. -* [s4cmd](https://github.com/bloomreach/s4cmd) - Super S3 command line tool, good for higher performance. -* [you-get](https://you-get.org/) - A YouTube/Youku/Niconico video downloader written in Python 3. -* [youtube-dl](https://rg3.github.io/youtube-dl/) - A small command-line program to download videos from YouTube. - -## E-commerce - -*Frameworks and libraries for e-commerce and payments.* +_Libraries for downloading._ -* [alipay](https://github.com/lxneng/alipay) - Unofficial Alipay API for Python. -* [Cartridge](https://github.com/stephenmcd/cartridge) - A shopping cart app built using the Mezzanine. -* [django-oscar](http://oscarcommerce.com/) - An open-source e-commerce framework for Django. -* [django-shop](https://github.com/awesto/django-shop) - A Django based shop system. -* [merchant](https://github.com/agiliq/merchant) - A Django app to accept payments from various payment processors. -* [money](https://github.com/carlospalol/money) - Money class with optional CLDR-backed locale-aware formatting and an extensible currency exchange solution. -* [python-currencies](https://github.com/Alir3z4/python-currencies) - Display money format and its filthy currencies. -* [forex-python](https://github.com/MicroPyramid/forex-python) - Foreign exchange rates, Bitcoin price index and currency conversion. -* [saleor](http://getsaleor.com/) - An e-commerce storefront for Django. -* [shoop](https://www.shuup.com/en/) - An open source E-Commerce platform based on Django. +- General + - [s3cmd](https://github.com/s3tools/s3cmd) - A command line tool for managing Amazon S3 and CloudFront. + - [youtube-dl](https://github.com/ytdl-org/youtube-dl/) - A command-line program to download videos from YouTube and other video sites. +- Financial Data + - [akshare](https://github.com/jindaxiang/akshare) - A financial data interface library, built for human beings! + - [edgartools](https://github.com/dgunning/edgartools) - Library for downloading structured data from SEC EDGAR filings and XBRL financial statements. + - [openbb](https://github.com/OpenBB-finance/OpenBB) - A financial data platform for analysts, quants and AI agents. + - [yfinance](https://github.com/ranaroussi/yfinance) - Easy Pythonic way to download market and financial data from Yahoo Finance. ## Editor Plugins and IDEs -* Emacs - * [elpy](https://github.com/jorgenschaefer/elpy) - Emacs Python Development Environment. -* Sublime Text - * [anaconda](https://github.com/DamnWidget/anaconda) - Anaconda turns your Sublime Text 3 in a full featured Python development IDE. - * [SublimeJEDI](https://github.com/srusskih/SublimeJEDI) - A Sublime Text plugin to the awesome auto-complete library Jedi. -* Vim - * [jedi-vim](https://github.com/davidhalter/jedi-vim) - Vim bindings for the Jedi auto-completion library for Python. - * [python-mode](https://github.com/python-mode/python-mode) - An all in one plugin for turning Vim into a Python IDE. - * [YouCompleteMe](https://github.com/Valloric/YouCompleteMe) - Includes [Jedi](https://github.com/davidhalter/jedi)-based completion engine for Python. -* Visual Studio - * [PTVS](https://github.com/Microsoft/PTVS) - Python Tools for Visual Studio. -* Visual Studio Code - * [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) - An extension with rich support for the Python language, with features including linting, IntelliSense, formatting, refactoring, debugging, unit tests, and jupyter support. -* IDE - * [PyCharm](https://www.jetbrains.com/pycharm/) - Commercial Python IDE by JetBrains. Has free community edition available. - * [spyder](https://github.com/spyder-ide/spyder) - Open Source Python IDE. +- Emacs + - [elpy](https://github.com/jorgenschaefer/elpy) - Emacs Python Development Environment. +- Vim + - [jedi-vim](https://github.com/davidhalter/jedi-vim) - Vim bindings for the Jedi auto-completion library for Python. + - [python-mode](https://github.com/python-mode/python-mode) - An all in one plugin for turning Vim into a Python IDE. + - [YouCompleteMe](https://github.com/Valloric/YouCompleteMe) - Includes [Jedi](https://github.com/davidhalter/jedi)-based completion engine for Python. +- Visual Studio + - [PTVS](https://github.com/Microsoft/PTVS) - Python Tools for Visual Studio. +- Visual Studio Code + - [Python for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-python.python) - The official VSCode extension with rich support for Python. +- IDE + - [PyCharm](https://www.jetbrains.com/pycharm/) - Commercial Python IDE by JetBrains. Has free community edition available. + - [spyder](https://github.com/spyder-ide/spyder) - Open Source Python IDE. ## Email -*Libraries for sending and parsing email.* +_Libraries for sending and parsing email._ -* [envelopes](http://tomekwojcik.github.io/envelopes/) - Mailing for human beings. -* [flanker](https://github.com/mailgun/flanker) - A email address and Mime parsing library. -* [imbox](https://github.com/martinrusev/imbox) - Python IMAP for Humans. -* [inbox.py](https://github.com/kennethreitz/inbox.py) - Python SMTP Server for Humans. -* [lamson](https://github.com/zedshaw/lamson) - Pythonic SMTP Application Server. -* [Marrow Mailer](https://github.com/marrow/mailer) - High-performance extensible mail delivery framework. -* [modoboa](https://github.com/modoboa/modoboa) - A mail hosting and management platform including a modern and simplified Web UI. -* [Nylas Sync Engine](https://github.com/nylas/sync-engine) - Providing a RESTful API on top of a powerful email sync platform. -* [yagmail](https://github.com/kootenpv/yagmail) - Yet another Gmail/SMTP client. +- Mail Servers + - [modoboa](https://github.com/modoboa/modoboa) - A mail hosting and management platform including a modern Web UI. +- Clients + - [imbox](https://github.com/martinrusev/imbox) - Python IMAP for Humans. + - [yagmail](https://github.com/kootenpv/yagmail) - Yet another Gmail/SMTP client. +- Others + - [flanker](https://github.com/mailgun/flanker) - An email address and Mime parsing library. + - [mailer](https://github.com/marrow/mailer) - High-performance extensible mail delivery framework. ## Environment Management -*Libraries for Python version and environment management.* - -* [pipenv](https://github.com/kennethreitz/pipenv) - Sacred Marriage of Pipfile, Pip, & Virtualenv. -* [poetry](https://github.com/sdispater/poetry) - Python dependency management and packaging made easy. -* [pyenv](https://github.com/pyenv/pyenv) - Simple Python version management. -* [venv](https://docs.python.org/3/library/venv.html) - (Python standard library in Python 3.3+) Creating lightweight virtual environments. -* [virtualenv](https://pypi.python.org/pypi/virtualenv) - A tool to create isolated Python environments. - -## Files - -*Libraries for file manipulation and MIME type detection.* +_Libraries for Python version and virtual environment management._ -* [mimetypes](https://docs.python.org/3/library/mimetypes.html) - (Python standard library) Map filenames to MIME types. -* [path.py](https://github.com/jaraco/path.py) - A module wrapper for [os.path](https://docs.python.org/3/library/os.path.html). -* [pathlib](https://docs.python.org/3/library/pathlib.html) - (Python standard library) An cross-platform, object-oriented path library. -* [PyFilesystem2](https://github.com/pyfilesystem/pyfilesystem2) - Python's filesystem abstraction layer. -* [python-magic](https://github.com/ahupp/python-magic) - A Python interface to the libmagic file type identification library. -* [Unipath](https://github.com/mikeorr/Unipath) - An object-oriented approach to file/directory operations. -* [watchdog](https://github.com/gorakhargosh/watchdog) - API and shell utilities to monitor file system events. +- [pyenv-win](https://github.com/pyenv-win/pyenv-win) - Pyenv for Windows, Simple Python version management. +- [pyenv](https://github.com/pyenv/pyenv) - Simple Python version management. +- [virtualenv](https://github.com/pypa/virtualenv) - A tool to create isolated Python environments. -## Foreign Function Interface +## File Manipulation -*Libraries for providing foreign function interface.* +_Libraries for file manipulation._ -* [cffi](https://pypi.python.org/pypi/cffi) - Foreign Function Interface for Python calling C code. -* [ctypes](https://docs.python.org/3/library/ctypes.html) - (Python standard library) Foreign Function Interface for Python calling C code. -* [PyCUDA](https://mathema.tician.de/software/pycuda/) - A Python wrapper for Nvidia's CUDA API. -* [SWIG](http://www.swig.org/Doc1.3/Python.html) - Simplified Wrapper and Interface Generator. - -## Forms - -*Libraries for working with forms.* - -* [Deform](https://github.com/Pylons/deform) - Python HTML form generation library influenced by the formish form generation library. -* [django-bootstrap3](https://github.com/dyve/django-bootstrap3) - Bootstrap 3 integration with Django. -* [django-bootstrap4](https://github.com/zostera/django-bootstrap4) - Bootstrap 4 integration with Django. -* [django-crispy-forms](https://github.com/django-crispy-forms/django-crispy-forms) - A Django app which lets you create beautiful forms in a very elegant and DRY way. -* [django-remote-forms](https://github.com/WiserTogether/django-remote-forms) - A platform independent Django form serializer. -* [WTForms](https://github.com/wtforms/wtforms) - A flexible forms validation and rendering library. +- [mimetypes](https://docs.python.org/3/library/mimetypes.html) - (Python standard library) Map filenames to MIME types. +- [path.py](https://github.com/jaraco/path.py) - A module wrapper for [os.path](https://docs.python.org/3/library/os.path.html). +- [pathlib](https://docs.python.org/3/library/pathlib.html) - (Python standard library) A cross-platform, object-oriented path library. +- [python-magic](https://github.com/ahupp/python-magic) - A Python interface to the libmagic file type identification library. +- [watchdog](https://github.com/gorakhargosh/watchdog) - API and shell utilities to monitor file system events. +- [watchfiles](https://github.com/samuelcolvin/watchfiles) - Simple, modern and fast file watching and code reload in python. ## Functional Programming -*Functional Programming with Python.* - -* [Coconut](http://coconut-lang.org/) - Coconut is a variant of Python built for simple, elegant, Pythonic functional programming. -* [CyToolz](https://github.com/pytoolz/cytoolz/) - Cython implementation of Toolz: High performance functional utilities. -* [fn.py](https://github.com/kachayev/fn.py) - Functional programming in Python: implementation of missing features to enjoy FP. -* [funcy](https://github.com/Suor/funcy) - A fancy and practical functional tools. -* [Toolz](https://github.com/pytoolz/toolz) - A collection of functional utilities for iterators, functions, and dictionaries. - -## GUI - -*Libraries for working with graphical user interface applications.* - -* [curses](https://docs.python.org/3/library/curses.html) - Built-in wrapper for [ncurses](http://www.gnu.org/software/ncurses/) used to create terminal GUI applications. -* [Eel](https://github.com/ChrisKnott/Eel) - Little library for making simple Electron-like offline HTML/JS GUI apps, with full access to Python capabilities and libraries. -* [enaml](https://github.com/nucleic/enaml) - Creating beautiful user-interfaces with Declaratic Syntax like QML. -* [Flexx](https://github.com/zoofIO/flexx) - Flexx is a pure Python toolkit for creating GUI's, that uses web technology for its rendering. -* [Gooey](https://github.com/chriskiehl/Gooey) - Turn command line programs into a full GUI application with one line. -* [kivy](https://kivy.org/) - A library for creating NUI applications, running on Windows, Linux, Mac OS X, Android and iOS. -* [pyglet](https://bitbucket.org/pyglet/pyglet/wiki/Home) - A cross-platform windowing and multimedia library for Python. -* [PyGObject](https://wiki.gnome.org/Projects/PyGObject) - Python Bindings for GLib/GObject/GIO/GTK+ (GTK+3). -* [PyQt](https://riverbankcomputing.com/software/pyqt/intro) - Python bindings for the [Qt](https://www.qt.io/) cross-platform application and UI framework, with support for both Qt v4 and Qt v5 frameworks. -* [PySide](https://wiki.qt.io/PySide) - Python bindings for the [Qt](http://www.qt.io/) cross-platform application and UI framework, supporting the Qt v4 framework. -* [PySimpleGUI](https://github.com/PySimpleGUI/PySimpleGUI) - Wrapper for tkinter, Qt, WxPython and Remi that creates a unified, easy to understand & more Python-like interface for beginner and intermediate level custom GUIs. -* [pywebview](https://github.com/r0x0r/pywebview/) - A lightweight cross-platform native wrapper around a webview component that allows to display HTML content in its own native dedicated window. -* [Tkinter](https://wiki.python.org/moin/TkInter) - Tkinter is Python's de-facto standard GUI package. -* [Toga](https://github.com/pybee/toga) - A Python native, OS native GUI toolkit. -* [urwid](http://urwid.org/) - A library for creating terminal GUI applications with strong support for widgets, events, rich colors, etc. -* [wxPython](https://wxpython.org/) - A blending of the wxWidgets C++ class library with the Python. +_Functional Programming with Python._ + +- [coconut](https://github.com/evhub/coconut) - A variant of Python built for simple, elegant, Pythonic functional programming. +- [cytoolz](https://github.com/pytoolz/cytoolz/) - Cython implementation of `Toolz`: High performance functional utilities. +- [functools](https://docs.python.org/3/library/functools.html) - (Python standard library) Higher-order functions and operations on callable objects. +- [funcy](https://github.com/Suor/funcy) - A fancy and practical functional tools. +- [more-itertools](https://github.com/erikrose/more-itertools) - More routines for operating on iterables, beyond `itertools`. +- [returns](https://github.com/dry-python/returns) - A set of type-safe monads, transformers, and composition utilities. +- [toolz](https://github.com/pytoolz/toolz) - A collection of functional utilities for iterators, functions, and dictionaries. + +## GUI Development + +_Libraries for working with graphical user interface applications._ + +- [curses](https://docs.python.org/3/library/curses.html) - Built-in wrapper for [ncurses](http://www.gnu.org/software/ncurses/) used to create terminal GUI applications. +- [customtkinter](https://github.com/tomschimansky/customtkinter) - A modern and customizable python UI-library based on Tkinter. +- [dearpygui](https://github.com/RaylockLLC/DearPyGui/) - A Simple GPU accelerated Python GUI framework +- [enaml](https://github.com/nucleic/enaml) - Creating beautiful user-interfaces with Declarative Syntax like QML. +- [flet](https://github.com/flet-dev/flet) - Cross-platform GUI framework for building modern apps in pure Python. +- [flexx](https://github.com/zoofIO/flexx) - Flexx is a pure Python toolkit for creating GUI's, that uses web technology for its rendering. +- [gooey](https://github.com/chriskiehl/Gooey) - Turn command line programs into a full GUI application with one line. +- [kivy](https://github.com/kivy/kivy) - A library for creating NUI applications, running on Windows, Linux, Mac OS X, Android and iOS. +- [nicegui](https://github.com/zauberzeug/nicegui) - An easy-to-use, Python-based UI framework, which shows up in your web browser. +- [pyglet](https://github.com/pyglet/pyglet) - A cross-platform windowing and multimedia library for Python. +- [pygobject](https://github.com/GNOME/pygobject) - Python Bindings for GLib/GObject/GIO/GTK+ (GTK+3). +- [PyQt](https://www.riverbankcomputing.com/static/Docs/PyQt6/) - Python bindings for the [Qt](https://www.qt.io/) cross-platform application and UI framework. +- [pyside](https://github.com/pyside/pyside-setup) - Qt for Python offers the official Python bindings for [Qt](https://www.qt.io/), this is same as PyQt but it's the official binding with different licensing. +- [pywebview](https://github.com/r0x0r/pywebview/) - A lightweight cross-platform native wrapper around a webview component. +- [tkinter](https://docs.python.org/3/library/tkinter.html) - (Python standard library) The standard Python interface to the Tcl/Tk GUI toolkit. +- [toga](https://github.com/pybee/toga) - A Python native, OS native GUI toolkit. +- [urwid](https://github.com/urwid/urwid) - A library for creating terminal GUI applications with strong support for widgets, events, rich colors, etc. +- [wxPython](https://github.com/wxWidgets/Phoenix) - A blending of the wxWidgets C++ class library with the Python. + +## GraphQL + +_Libraries for working with GraphQL._ + +- [graphene](https://github.com/graphql-python/graphene/) - GraphQL framework for Python. +- [strawberry-django](https://github.com/strawberry-graphql/strawberry-django) - Strawberry GraphQL integration with Django. ## Game Development -*Awesome game development libraries.* +_Awesome game development libraries._ -* [Cocos2d](http://cocos2d.org/) - cocos2d is a framework for building 2D games, demos, and other graphical/interactive applications. It is based on pyglet. -* [Harfang3D](http://www.harfang3d.com) - Python framework for 3D, VR and game development. Manage and display complex 3D scenes, with physics, video, sound and music, access VR devices. All written in C++. -* [Panda3D](https://www.panda3d.org/) - 3D game engine developed by Disney and maintained by Carnegie Mellon's Entertainment Technology Center. Written in C++, completely wrapped in Python. -* [Pygame](http://www.pygame.org/news.html) - Pygame is a set of Python modules designed for writing games. -* [PyOgre](http://www.ogre3d.org/tikiwiki/PyOgre) - Python bindings for the Ogre 3D render engine, can be used for games, simulations, anything 3D. -* [PyOpenGL](http://pyopengl.sourceforge.net/) - Python ctypes bindings for OpenGL and it's related APIs. -* [PySDL2](https://pysdl2.readthedocs.io) - A ctypes based wrapper for the SDL2 library. -* [RenPy](https://www.renpy.org/) - A Visual Novel engine. +- [arcade](https://github.com/pythonarcade/arcade) - Arcade is a modern Python framework for crafting games with compelling graphics and sound. +- [cocos](https://github.com/los-cocos/cocos) - A framework for building 2D games, demos, and other graphical/interactive applications. +- [harfang3d](https://github.com/harfang3d/harfang3d) - Python framework for 3D, VR and game development. +- [panda3d](https://github.com/panda3d/panda3d) - 3D game engine developed by Disney. +- [pygame](https://github.com/pygame/pygame) - Pygame is a set of Python modules designed for writing games. +- [pyopengl](https://github.com/mcfletch/pyopengl) - Python ctypes bindings for OpenGL and it's related APIs. +- [py-sdl2](https://github.com/py-sdl/py-sdl2) - A ctypes based wrapper for the SDL2 library. +- [renpy](https://github.com/renpy/renpy) - A Visual Novel engine. ## Geolocation -*Libraries for geocoding addresses and working with latitudes and longitudes.* +_Libraries for geocoding addresses and working with latitudes and longitudes._ -* [django-countries](https://github.com/SmileyChris/django-countries) - A Django app that provides country choices for use with forms, flag icons static files, and a country field for models. -* [GeoDjango](https://docs.djangoproject.com/en/dev/ref/contrib/gis/) - A world-class geographic web framework. -* [GeoIP](https://github.com/maxmind/geoip-api-python) - Python API for MaxMind GeoIP Legacy Database. -* [geojson](https://github.com/frewsxcv/python-geojson) - Python bindings and utilities for GeoJSON. -* [geopy](https://github.com/geopy/geopy) - Python Geocoding Toolbox. -* [pygeoip](https://github.com/appliedsec/pygeoip) - Pure Python GeoIP API. +- [django-countries](https://github.com/SmileyChris/django-countries) - A Django app that provides a country field for models and forms. +- [geodjango](https://docs.djangoproject.com/en/dev/ref/contrib/gis/) - A world-class geographic web framework. +- [geojson](https://github.com/jazzband/geojson) - Python bindings and utilities for GeoJSON. +- [geopandas](https://github.com/geopandas/geopandas) - Python tools for geographic data (GeoSeries/GeoDataFrame) built on pandas. +- [geopy](https://github.com/geopy/geopy) - Python Geocoding Toolbox. ## HTML Manipulation -*Libraries for working with HTML and XML.* +_Libraries for working with HTML and XML._ -* [BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) - Providing Pythonic idioms for iterating, searching, and modifying HTML or XML. -* [bleach](https://github.com/mozilla/bleach) - A whitelist-based HTML sanitization and text linkification library. -* [cssutils](https://pypi.python.org/pypi/cssutils/) - A CSS library for Python. -* [html5lib](https://github.com/html5lib/html5lib-python) - A standards-compliant library for parsing and serializing HTML documents and fragments. -* [lxml](http://lxml.de/) - A very fast, easy-to-use and versatile library for handling HTML and XML. -* [MarkupSafe](https://github.com/pallets/markupsafe) - Implements a XML/HTML/XHTML Markup safe string for Python. -* [pyquery](https://github.com/gawel/pyquery) - A jQuery-like library for parsing HTML. -* [untangle](https://github.com/stchris/untangle) - Converts XML documents to Python objects for easy access. -* [WeasyPrint](http://weasyprint.org) - A visual rendering engine for HTML and CSS that can export to PDF. -* [xmldataset](https://xmldataset.readthedocs.io/en/latest/) - Simple XML Parsing. -* [xmltodict](https://github.com/martinblech/xmltodict) - Working with XML feel like you are working with JSON. +- [beautifulsoup](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) - Providing Pythonic idioms for iterating, searching, and modifying HTML or XML. +- [cssutils](https://github.com/jaraco/cssutils) - A CSS library for Python. +- [html5lib](https://github.com/html5lib/html5lib-python) - A standards-compliant library for parsing and serializing HTML documents and fragments. +- [justhtml](https://github.com/EmilStenstrom/justhtml/) - A pure Python HTML5 parser that just works. +- [lxml](https://github.com/lxml/lxml) - A very fast, easy-to-use and versatile library for handling HTML and XML. +- [markupsafe](https://github.com/pallets/markupsafe) - Implements a XML/HTML/XHTML Markup safe string for Python. +- [pyquery](https://github.com/gawel/pyquery) - A jQuery-like library for parsing HTML. +- [untangle](https://github.com/stchris/untangle) - Converts XML documents to Python objects for easy access. +- [weasyprint](https://github.com/Kozea/WeasyPrint) - A visual rendering engine for HTML and CSS that can export to PDF. +- [xmldataset](https://github.com/spurin/xmldataset) - Simple XML Parsing. +- [xmltodict](https://github.com/martinblech/xmltodict) - Working with XML feel like you are working with JSON. -## HTTP +## HTTP Clients -*Libraries for working with HTTP.* +_Libraries for working with HTTP._ -* [grequests](https://github.com/kennethreitz/grequests) - requests + gevent for asynchronous HTTP requests. -* [httplib2](https://github.com/httplib2/httplib2) - Comprehensive HTTP client library. -* [requests](http://docs.python-requests.org/en/latest/) - HTTP Requests for Humans™. -* [treq](https://github.com/twisted/treq) - Python requests like API built on top of Twisted's HTTP client. -* [urllib3](https://github.com/shazow/urllib3) - A HTTP library with thread-safe connection pooling, file post support, sanity friendly. +- [httpx](https://github.com/encode/httpx) - A next generation HTTP client for Python. +- [requests](https://github.com/psf/requests) - HTTP Requests for Humans. +- [treq](https://github.com/twisted/treq) - Python requests like API built on top of Twisted's HTTP client. +- [urllib3](https://github.com/urllib3/urllib3) - A HTTP library with thread-safe connection pooling, file post support, sanity friendly. ## Hardware -*Libraries for programming with hardware.* +_Libraries for programming with hardware._ -* [ino](http://inotool.org/) - Command line toolkit for working with [Arduino](https://www.arduino.cc/). -* [keyboard](https://github.com/boppreh/keyboard) - Hook and simulate global keyboard events on Windows and Linux. -* [mouse](https://github.com/boppreh/mouse) - Hook and simulate global mouse events on Windows and Linux. -* [Pingo](http://www.pingo.io/) - Pingo provides a uniform API to program devices like the Raspberry Pi, pcDuino, Intel Galileo, etc. -* [PyUserInput](https://github.com/SavinaRoja/PyUserInput) - A module for cross-platform control of the mouse and keyboard. -* [scapy](https://github.com/secdev/scapy) - A brilliant packet manipulation library. -* [wifi](https://github.com/rockymeza/wifi) - A Python library and command line tool for working with WiFi on Linux. +- [bleak](https://github.com/hbldh/bleak) - A cross platform Bluetooth Low Energy Client for Python using asyncio. +- [mouse](https://github.com/boppreh/mouse) - Hook and simulate global mouse events on Windows and Linux. +- [pynput](https://github.com/moses-palmer/pynput) - A library to control and monitor input devices. +- [scapy](https://github.com/secdev/scapy) - A brilliant packet manipulation library. ## Image Processing -*Libraries for manipulating images.* - -* [hmap](https://github.com/rossgoodwin/hmap) - Image histogram remapping. -* [imgSeek](https://sourceforge.net/projects/imgseek/) - A project for searching a collection of images using visual similarity. -* [nude.py](https://github.com/hhatto/nude.py) - Nudity detection. -* [pagan](https://github.com/daboth/pagan) - Retro identicon (Avatar) generation based on input string and hash. -* [pillow](https://github.com/python-pillow/Pillow) - Pillow is the friendly [PIL](http://www.pythonware.com/products/pil/) fork. -* [pyBarcode](https://pythonhosted.org/pyBarcode/) - Create barcodes in Python without needing PIL. -* [pygram](https://github.com/ajkumar25/pygram) - Instagram-like image filters. -* [python-qrcode](https://github.com/lincolnloop/python-qrcode) - A pure Python QR Code generator. -* [Quads](https://github.com/fogleman/Quads) - Computer art based on quadtrees. -* [scikit-image](http://scikit-image.org/) - A Python library for (scientific) image processing. -* [thumbor](https://github.com/thumbor/thumbor) - A smart imaging service. It enables on-demand crop, re-sizing and flipping of images. -* [wand](https://github.com/dahlia/wand) - Python bindings for [MagickWand](http://www.imagemagick.org/script/magick-wand.php), C API for ImageMagick. +_Libraries for manipulating images._ + +- [pillow](https://github.com/python-pillow/Pillow) - Pillow is the friendly [PIL](http://www.pythonware.com/products/pil/) fork. +- [pymatting](https://github.com/pymatting/pymatting) - A library for alpha matting. +- [python-barcode](https://github.com/WhyNotHugo/python-barcode) - Create barcodes in Python with no extra dependencies. +- [python-qrcode](https://github.com/lincolnloop/python-qrcode) - A pure Python QR Code generator. +- [pyvips](https://github.com/libvips/pyvips) - A fast image processing library with low memory needs. +- [quads](https://github.com/fogleman/Quads) - Computer art based on quadtrees. +- [scikit-image](https://github.com/scikit-image/scikit-image) - A Python library for (scientific) image processing. +- [thumbor](https://github.com/thumbor/thumbor) - A smart imaging service. It enables on-demand crop, re-sizing and flipping of images. +- [wand](https://github.com/emcconville/wand) - Python bindings for [MagickWand](http://www.imagemagick.org/script/magick-wand.php), C API for ImageMagick. ## Implementations -*Implementations of Python.* - -* [CLPython](https://github.com/metawilm/cl-python) - Implementation of the Python programming language written in Common Lisp. -* [CPython](https://github.com/python/cpython) - **Default, most widely used implementation of the Python programming language written in C.** -* [Cython](http://cython.org/) - Optimizing Static Compiler for Python. Uses type mixins to compile Python into C or C++ modules resulting in large performance gains -* [Grumpy](https://github.com/google/grumpy) - More compiler than interpreter as more powerful CPython2.7 replacement (alpha). -* [IronPython](https://github.com/IronLanguages/ironpython3) - Implementation of the Python programming language written in C# targeting the .NET Framework and Mono. -* [Jython](https://hg.python.org/jython) - Implementation of Python programming language written in Java for the Java virtual machine (JVM). -* [MicroPython](https://github.com/micropython/micropython) - MicroPython - a lean and efficient Python programming language implementation for microcontrollers and constrained systems -* [Numba](http://numba.pydata.org/) - Python JIT compiler to LLVM aimed at scientific Python. -* [PeachPy](https://github.com/Maratyszcza/PeachPy) - x86-64 assembler embedded in Python. Can be used as inline assembler for Python or as a stand-alone assembler for Windows, Linux, OS X, Native Client and Go. -* [Pyjion](https://github.com/Microsoft/Pyjion) - A JIT for Python based upon CoreCLR. -* [PyPy](https://bitbucket.org/pypy/pypy) - Implementation of the Python programming language written in RPython and translated into C. PyPy focuses on speed, efficiency and compatibility with the original CPython interpreter. The interpreter uses black magic to make Python very fast without having to add in additional type information. -* [PySec](https://github.com/ebranca/owasp-pysec) - Hardened version of python that makes it easier for security professionals and developers to write applications more resilient to attacks and manipulations. -* [Pyston](https://github.com/dropbox/pyston) - A Python implementation built using LLVM and modern JIT techniques with the goal of achieving good performance. -* [Stackless Python](https://github.com/stackless-dev/stackless/wiki) - An enhanced version of the Python programming language which allows programmers to reap the benefits of thread-based programming without the performance and complexity problems associated with conventional threads. +_Implementations of Python._ + +- [clpython](https://github.com/metawilm/cl-python) - Implementation of the Python programming language written in Common Lisp. +- [cpython](https://github.com/python/cpython) - Default, most widely used implementation of the Python programming language written in C. +- [cython](https://github.com/cython/cython) - Optimizing Static Compiler for Python. +- [ironpython](https://github.com/IronLanguages/ironpython3) - Implementation of the Python programming language written in C#. +- [micropython](https://github.com/micropython/micropython) - A lean and efficient Python programming language implementation. +- [numba](https://github.com/numba/numba) - Python JIT compiler to LLVM aimed at scientific Python. +- [PeachPy](https://github.com/Maratyszcza/PeachPy) - x86-64 assembler embedded in Python. +- [pypy](https://github.com/pypy/pypy) - A very fast and compliant implementation of the Python language. +- [pyston](https://github.com/pyston/pyston/) - A Python implementation using JIT techniques. ## Interactive Interpreter -*Interactive Python interpreters (REPL).* +_Interactive Python interpreters (REPL)._ -* [bpython](https://github.com/bpython/bpython) - A fancy interface to the Python interpreter. -* [Jupyter Notebook (IPython)](https://jupyter.org) - A rich toolkit to help you make the most out of using Python interactively. - * [awesome-jupyter](https://github.com/markusschanta/awesome-jupyter) -* [ptpython](https://github.com/jonathanslenders/ptpython) - Advanced Python REPL built on top of the [python-prompt-toolkit](https://github.com/jonathanslenders/python-prompt-toolkit). +- [bpython](https://github.com/bpython/bpython) - A fancy interface to the Python interpreter. +- [jupyter](https://github.com/jupyter/notebook) - A rich toolkit to help you make the most out of using Python interactively. + - [awesome-jupyter](https://github.com/markusschanta/awesome-jupyter) +- [marimo](https://github.com/marimo-team/marimo) - Transform data and train models, feels like a next-gen notebook, stored as Git-friendly Python. +- [ptpython](https://github.com/jonathanslenders/ptpython) - Advanced Python REPL built on top of the [python-prompt-toolkit](https://github.com/jonathanslenders/python-prompt-toolkit). ## Internationalization -*Libraries for working with i18n.* +_Libraries for working with i18n._ -* [Babel](http://babel.pocoo.org/en/latest/) - An internationalization library for Python. -* [PyICU](https://github.com/ovalhub/pyicu) - A wrapper of International Components for Unicode C++ library ([ICU](http://site.icu-project.org/)). +- [babel](https://github.com/python-babel/babel) - An internationalization library for Python. ## Job Scheduler -*Libraries for scheduling jobs.* +_Libraries for scheduling jobs._ -* [APScheduler](http://apscheduler.readthedocs.io/en/latest/) - A light but powerful in-process task scheduler that lets you schedule functions. -* [django-schedule](https://github.com/thauber/django-schedule) - A calendaring app for Django. -* [doit](http://pydoit.org/) - A task runner and build tool. -* [gunnery](https://github.com/gunnery/gunnery) - Multipurpose task execution tool for distributed systems with web-based interface. -* [Joblib](http://pythonhosted.org/joblib/index.html) - A set of tools to provide lightweight pipelining in Python. -* [Plan](https://github.com/fengsp/plan) - Writing crontab file in Python like a charm. -* [schedule](https://github.com/dbader/schedule) - Python job scheduling for humans. -* [Spiff](https://github.com/knipknap/SpiffWorkflow) - A powerful workflow engine implemented in pure Python. -* [TaskFlow](https://docs.openstack.org/developer/taskflow/) - A Python library that helps to make task execution easy, consistent and reliable. -* [Airflow](https://airflow.apache.org/) - Airflow is a platform to programmatically author, schedule and monitor workflows. +- [airflow](https://github.com/apache/airflow) - Airflow is a platform to programmatically author, schedule and monitor workflows. +- [apscheduler](https://github.com/agronholm/apscheduler) - A light but powerful in-process task scheduler that lets you schedule functions. +- [django-schedule](https://github.com/thauber/django-schedule) - A calendaring app for Django. +- [doit](https://github.com/pydoit/doit) - A task runner and build tool. +- [joblib](https://github.com/joblib/joblib) - A set of tools to provide lightweight pipelining in Python. +- [plan](https://github.com/fengsp/plan) - Writing crontab file in Python like a charm. +- [prefect](https://github.com/PrefectHQ/prefect) - A modern workflow orchestration framework that makes it easy to build, schedule and monitor robust data pipelines. +- [schedule](https://github.com/dbader/schedule) - Python job scheduling for humans. +- [SpiffWorkflow](https://github.com/knipknap/SpiffWorkflow) - A powerful workflow engine implemented in pure Python. +- [taskflow](https://docs.openstack.org/developer/taskflow/) - A Python library that helps to make task execution easy, consistent and reliable. ## Logging -*Libraries for generating and working with logs.* +_Libraries for generating and working with logs._ -* [Eliot](https://github.com/ScatterHQ/eliot) - Logging for complex & distributed systems. -* [logbook](http://logbook.readthedocs.io/en/stable/) - Logging replacement for Python. -* [logging](https://docs.python.org/3/library/logging.html) - (Python standard library) Logging facility for Python. -* [raven](https://github.com/getsentry/raven-python) - Python client for Sentry, a log/error tracking, crash reporting and aggregation platform for web applications. +- [logbook](https://github.com/getlogbook/logbook) - Logging replacement for Python. +- [logging](https://docs.python.org/3/library/logging.html) - (Python standard library) Logging facility for Python. +- [loguru](https://github.com/Delgan/loguru) - Library which aims to bring enjoyable logging in Python. +- [sentry-python](https://github.com/getsentry/sentry-python) - Sentry SDK for Python. +- [structlog](https://github.com/hynek/structlog) - Structured logging made easy. ## Machine Learning -*Libraries for Machine Learning. See: [awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning#python).* - -* [H2O](https://github.com/h2oai/h2o-3) - Open Source Fast Scalable Machine Learning Platform. -* [Metrics](https://github.com/benhamner/Metrics) - Machine learning evaluation metrics. -* [NuPIC](https://github.com/numenta/nupic) - Numenta Platform for Intelligent Computing. -* [scikit-learn](http://scikit-learn.org/) - The most popular Python library for Machine Learning. -* [Spark ML](http://spark.apache.org/docs/latest/ml-guide.html) - [Apache Spark](http://spark.apache.org/)'s scalable Machine Learning library. -* [vowpal_porpoise](https://github.com/josephreisinger/vowpal_porpoise) - A lightweight Python wrapper for [Vowpal Wabbit](https://github.com/JohnLangford/vowpal_wabbit/). -* [xgboost](https://github.com/dmlc/xgboost) - A scalable, portable, and distributed gradient boosting library. +_Libraries for Machine Learning. Also see [awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning#python)._ + +- [diffusers](https://github.com/huggingface/diffusers) - A library that provides pretrained diffusion models for generating and editing images, audio, and video. +- [feature_engine](https://github.com/feature-engine/feature_engine) - sklearn compatible API with the widest toolset for feature engineering and selection. +- [gym](https://github.com/openai/gym) - A toolkit for developing and comparing reinforcement learning algorithms. +- [h2o](https://github.com/h2oai/h2o-3) - Open Source Fast Scalable Machine Learning Platform. +- [metrics](https://github.com/benhamner/Metrics) - Machine learning evaluation metrics. +- [mindsdb](https://github.com/mindsdb/mindsdb) - MindsDB is an open source AI layer for existing databases that allows you to effortlessly develop, train and deploy state-of-the-art machine learning models using standard queries. +- [pgmpy](https://github.com/pgmpy/pgmpy) - A Python library for probabilistic graphical models and Bayesian networks. +- [rasa](https://github.com/RasaHQ/rasa) - An open-source machine learning framework for automated text and voice-based conversations. +- [scikit-learn](https://github.com/scikit-learn/scikit-learn) - The most popular Python library for Machine Learning with extensive documentation and community support. +- [spark.ml](http://spark.apache.org/docs/latest/ml-guide.html) - [Apache Spark](http://spark.apache.org/)'s scalable Machine Learning library for distributed computing. +- [transformers](https://github.com/huggingface/transformers) - A framework that lets you easily use pretrained transformer models for NLP, vision, and audio tasks. +- [xgboost](https://github.com/dmlc/xgboost) - A scalable, portable, and distributed gradient boosting library. ## Microsoft Windows -*Python programming on Microsoft Windows.* +_Python programming on Microsoft Windows._ -* [Python(x,y)](http://python-xy.github.io/) - Scientific-applications-oriented Python Distribution based on Qt and Spyder. -* [pythonlibs](http://www.lfd.uci.edu/~gohlke/pythonlibs/) - Unofficial Windows binaries for Python extension packages. -* [PythonNet](https://github.com/pythonnet/pythonnet) - Python Integration with the .NET Common Language Runtime (CLR). -* [PyWin32](https://sourceforge.net/projects/pywin32/) - Python Extensions for Windows. -* [WinPython](https://winpython.github.io/) - Portable development environment for Windows 7/8. +- [pythonnet](https://github.com/pythonnet/pythonnet) - Python Integration with the .NET Common Language Runtime (CLR). +- [pywin32](https://github.com/mhammond/pywin32) - Python Extensions for Windows. +- [winpython](https://github.com/winpython/winpython) - Portable development environment for Windows 10/11. ## Miscellaneous -*Useful libraries or tools that don't fit in the categories above.* +_Useful libraries or tools that don't fit in the categories above._ -* [blinker](https://github.com/jek/blinker) - A fast Python in-process signal/event dispatching system. -* [boltons](https://github.com/mahmoud/boltons) - A set of pure-Python utilities. -* [itsdangerous](https://github.com/pallets/itsdangerous) - Various helpers to pass trusted data to untrusted environments. -* [pluginbase](https://github.com/mitsuhiko/pluginbase) - A simple but flexible plugin system for Python. -* [tryton](http://www.tryton.org/) - A general purpose business framework. +- [blinker](https://github.com/jek/blinker) - A fast Python in-process signal/event dispatching system. +- [boltons](https://github.com/mahmoud/boltons) - A set of pure-Python utilities. +- [itsdangerous](https://github.com/pallets/itsdangerous) - Various helpers to pass trusted data to untrusted environments. +- [pluginbase](https://github.com/mitsuhiko/pluginbase) - A simple but flexible plugin system for Python. +- [tryton](https://github.com/tryton/tryton) - A general-purpose business framework. ## Natural Language Processing -*Libraries for working with human languages.* +_Libraries for working with human languages._ - General - * [gensim](https://github.com/RaRe-Technologies/gensim) - Topic Modelling for Humans. - * [langid.py](https://github.com/saffsd/langid.py) - Stand-alone language identification system. - * [nltk](http://www.nltk.org/) - A leading platform for building Python programs to work with human language data. - * [pattern](https://github.com/clips/pattern) - A web mining module for the Python. - * [polyglot](https://github.com/aboSamoor/polyglot) - Natural language pipeline supporting hundreds of languages. - * [pytext](https://github.com/facebookresearch/pytext) - A natural language modeling framework based on PyTorch. - * [PyTorch-NLP](https://github.com/PetrochukM/PyTorch-NLP) - A toolkit enabling rapid deep learning NLP prototyping for research. - * [spacy](https://spacy.io/) - A library for industrial-strength natural language processing in Python and Cython. - * [stanfordnlp](https://github.com/stanfordnlp/stanfordnlp) - The Stanford NLP Group's official Python library, supporting 50+ languages. + - [gensim](https://github.com/RaRe-Technologies/gensim) - Topic Modeling for Humans. + - [langid.py](https://github.com/saffsd/langid.py) - Stand-alone language identification system. + - [nltk](https://github.com/nltk/nltk) - A leading platform for building Python programs to work with human language data. + - [pattern](https://github.com/clips/pattern) - A web mining module. + - [polyglot](https://github.com/aboSamoor/polyglot) - Natural language pipeline supporting hundreds of languages. + - [spacy](https://github.com/explosion/spaCy) - A library for industrial-strength natural language processing in Python and Cython. + - [stanza](https://github.com/stanfordnlp/stanza) - The Stanford NLP Group's official Python library, supporting 60+ languages. - Chinese - * [jieba](https://github.com/fxsjy/jieba) - The most popular Chinese text segmentation library. - * [pkuseg-python](https://github.com/lancopku/pkuseg-python) - A toolkit for Chinese word segmentation in various domains. - * [snownlp](https://github.com/isnowfy/snownlp) - A library for processing Chinese text. - * [funNLP](https://github.com/fighting41love/funNLP) - A collection of tools and datasets for Chinese NLP. + - [funnlp](https://github.com/fighting41love/funNLP) - A collection of tools and datasets for Chinese NLP. + - [jieba](https://github.com/fxsjy/jieba) - The most popular Chinese text segmentation library. + - [pkuseg-python](https://github.com/lancopku/pkuseg-python) - A toolkit for Chinese word segmentation in various domains. + - [snownlp](https://github.com/isnowfy/snownlp) - A library for processing Chinese text. ## Network Virtualization -*Tools and libraries for Virtual Networking and SDN (Software Defined Networking).* - -* [mininet](https://github.com/mininet/mininet) - A popular network emulator and API written in Python. -* [pox](https://github.com/noxrepo/pox) - A Python-based SDN control applications, such as OpenFlow SDN controllers. +_Tools and libraries for Virtual Networking and SDN (Software Defined Networking)._ -## Networking - -*Libraries for networking programming.* - -* [asyncio](https://docs.python.org/3/library/asyncio.html) - (Python standard library) Asynchronous I/O, event loop, coroutines and tasks. - - [awesome-asyncio](https://github.com/timofurrer/awesome-asyncio) -* [pulsar](https://github.com/quantmind/pulsar) - Event-driven concurrent framework for Python. -* [pyzmq](https://github.com/zeromq/pyzmq) - A Python wrapper for the ZeroMQ message library. -* [Twisted](https://twistedmatrix.com/trac/) - An event-driven networking engine. -* [napalm](https://github.com/napalm-automation/napalm) - Cross-vendor API to manipulate network devices. - -## News Feed - -*Libraries for building user's activities.* - -* [django-activity-stream](https://github.com/justquick/django-activity-stream) - Generating generic activity streams from the actions on your site. -* [Stream Framework](https://github.com/tschellenbach/Stream-Framework) - Building newsfeed and notification systems using Cassandra and Redis. +- [mininet](https://github.com/mininet/mininet) - A popular network emulator and API written in Python. +- [napalm](https://github.com/napalm-automation/napalm) - Cross-vendor API to manipulate network devices. +- [pox](https://github.com/noxrepo/pox) - A Python-based SDN control applications, such as OpenFlow SDN controllers. ## ORM -*Libraries that implement Object-Relational Mapping or data mapping techniques.* - -* Relational Databases - * [Django Models](https://docs.djangoproject.com/en/dev/topics/db/models/) - A part of Django. - * [SQLAlchemy](https://www.sqlalchemy.org/) - The Python SQL Toolkit and Object Relational Mapper. - * [awesome-sqlalchemy](https://github.com/dahlia/awesome-sqlalchemy) - * [dataset](https://github.com/pudo/dataset) - Store Python dicts in a database - works with SQLite, MySQL, and PostgreSQL. - * [orator](https://github.com/sdispater/orator) - The Orator ORM provides a simple yet beautiful ActiveRecord implementation. - * [peewee](https://github.com/coleifer/peewee) - A small, expressive ORM. - * [pony](https://github.com/ponyorm/pony/) - ORM that provides a generator-oriented interface to SQL. - * [pydal](https://github.com/web2py/pydal/) - A pure Python Database Abstraction Layer. -* NoSQL Databases - * [hot-redis](https://github.com/stephenmcd/hot-redis) - Rich Python data types for Redis. - * [mongoengine](https://github.com/MongoEngine/mongoengine) - A Python Object-Document-Mapper for working with MongoDB. - * [PynamoDB](https://github.com/pynamodb/PynamoDB) - A Pythonic interface for [Amazon DynamoDB](https://aws.amazon.com/dynamodb/). - * [redisco](https://github.com/kiddouk/redisco) - A Python Library for Simple Models and Containers Persisted in Redis. +_Libraries that implement Object-Relational Mapping or data mapping techniques._ + +- Relational Databases + - [django.db.models](https://docs.djangoproject.com/en/dev/topics/db/models/) - The Django ORM. + - [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) - The Python SQL Toolkit and Object Relational Mapper. + - [awesome-sqlalchemy](https://github.com/dahlia/awesome-sqlalchemy) + - [dataset](https://github.com/pudo/dataset) - Store Python dicts in a database - works with SQLite, MySQL, and PostgreSQL. + - [peewee](https://github.com/coleifer/peewee) - A small, expressive ORM. + - [pony](https://github.com/ponyorm/pony/) - ORM that provides a generator-oriented interface to SQL. + - [pydal](https://github.com/web2py/pydal/) - A pure Python Database Abstraction Layer. + - [sqlmodel](https://github.com/fastapi/sqlmodel) - SQLModel is based on Python type annotations, and powered by Pydantic and SQLAlchemy. +- NoSQL Databases + - [beanie](https://github.com/BeanieODM/beanie) - An asynchronous Python object-document mapper (ODM) for MongoDB. + - [mongoengine](https://github.com/MongoEngine/mongoengine) - A Python Object-Document-Mapper for working with MongoDB. + - [odmantic](https://github.com/art049/odmantic) - Sync and Async ODM for MongoDB built on top of Pydantic for model definition and validation. + - [pynamodb](https://github.com/pynamodb/PynamoDB) - A Pythonic interface for [Amazon DynamoDB](https://aws.amazon.com/dynamodb/). ## Package Management -*Libraries for package and dependency management.* +_Libraries for package and dependency management._ -* [pip](https://pip.pypa.io/en/stable/) - The Python package and dependency manager. - * [PyPI](https://pypi.org/) - * [pip-tools](https://github.com/jazzband/pip-tools) - A set of tools to keep your pinned Python dependencies fresh. -* [conda](https://github.com/conda/conda/) - Cross-platform, Python-agnostic binary package manager. +- [pip](https://github.com/pypa/pip) - The package installer for Python. + - [pip-tools](https://github.com/jazzband/pip-tools) - A set of tools to keep your pinned Python dependencies fresh. +- [conda](https://github.com/conda/conda/) - Cross-platform, Python-agnostic binary package manager. +- [hatch](https://github.com/pypa/hatch) - Modern, extensible Python project management. +- [poetry](https://github.com/sdispater/poetry) - Python dependency management and packaging made easy. +- [uv](https://github.com/astral-sh/uv) - An extremely fast Python package and project manager, written in Rust. ## Package Repositories -*Local PyPI repository server and proxies.* +_Local PyPI repository server and proxies._ + +- [bandersnatch](https://github.com/pypa/bandersnatch/) - PyPI mirroring tool provided by Python Packaging Authority (PyPA). +- [devpi](https://github.com/devpi/devpi) - PyPI server and packaging/testing/release tool. +- [warehouse](https://github.com/pypa/warehouse) - Next generation Python Package Repository (PyPI). + +## Penetration Testing + +_Frameworks and tools for penetration testing._ -* [warehouse](https://github.com/pypa/warehouse) - Next generation Python Package Repository (PyPI). -* [bandersnatch](https://github.com/pypa/bandersnatch/) - PyPI mirroring tool provided by Python Packaging Authority (PyPA). -* [devpi](https://github.com/devpi/devpi) - PyPI server and packaging/testing/release tool. -* [localshop](https://github.com/jazzband/localshop) - Local PyPI server (custom packages and auto-mirroring of pypi). +- [fsociety](https://github.com/Manisso/fsociety) - A Penetration testing framework. +- [setoolkit](https://github.com/trustedsec/social-engineer-toolkit) - A toolkit for social engineering. +- [sherlock](https://github.com/sherlock-project/sherlock) - Hunt down social media accounts by username across social networks. +- [sqlmap](https://github.com/sqlmapproject/sqlmap) - Automatic SQL injection and database takeover tool. ## Permissions -*Libraries that allow or deny users access to data or functionality.* +_Libraries that allow or deny users access to data or functionality._ -* [django-guardian](https://github.com/django-guardian/django-guardian) - Implementation of per object permissions for Django 1.2+ -* [django-rules](https://github.com/dfunckt/django-rules) - A tiny but powerful app providing object-level permissions to Django, without requiring a database. +- [django-guardian](https://github.com/django-guardian/django-guardian) - Implementation of per object permissions for Django 1.2+ +- [django-rules](https://github.com/dfunckt/django-rules) - A tiny but powerful app providing object-level permissions to Django, without requiring a database. ## Processes -*Libraries for starting and communicating with OS processes.* +_Libraries for starting and communicating with OS processes._ -* [delegator.py](https://github.com/kennethreitz/delegator.py) - [Subprocesses](https://docs.python.org/3.6/library/subprocess.html) for Humans™ 2.0. -* [sarge](https://sarge.readthedocs.io/en/latest/) - Yet another wrapper for subprocess. -* [sh](https://github.com/amoffat/sh) - A full-fledged subprocess replacement for Python. +- [delegator.py](https://github.com/amitt001/delegator.py) - [Subprocesses](https://docs.python.org/3/library/subprocess.html) for Humans 2.0. +- [sarge](https://github.com/vsajip/sarge) - Yet another wrapper for subprocess. +- [sh](https://github.com/amoffat/sh) - A full-fledged subprocess replacement for Python. -## Queue +## Quantum Computing -*Libraries for working with event and task queues.* +_Libraries for quantum computing._ -* [celery](http://www.celeryproject.org/) - An asynchronous task queue/job queue based on distributed message passing. -* [huey](https://github.com/coleifer/huey) - Little multi-threaded task queue. -* [mrq](https://github.com/pricingassistant/mrq) - Mr. Queue - A distributed worker task queue in Python using Redis & gevent. -* [rq](https://github.com/rq/rq) - Simple job queues for Python. +- [Cirq](https://github.com/quantumlib/Cirq) — A Google-developed framework focused on hardware-aware quantum circuit design for NISQ devices. +- [pennylane](https://github.com/PennyLaneAI/pennylane) — A hybrid quantum-classical machine learning library with automatic differentiation support. +- [qiskit](https://github.com/Qiskit/qiskit) — An IBM-backed quantum SDK for building, simulating, and running circuits on real quantum hardware. +- [qutip](https://github.com/qutip/qutip) - Quantum Toolbox in Python. ## Recommender Systems -*Libraries for building recommender systems.* +_Libraries for building recommender systems._ -* [annoy](https://github.com/spotify/annoy) - Approximate Nearest Neighbors in C++/Python optimized for memory usage. -* [fastFM](https://github.com/ibayer/fastFM) - A library for Factorization Machines. -* [implicit](https://github.com/benfred/implicit) - A fast Python implementation of collaborative filtering for implicit datasets. -* [libffm](https://github.com/guestwalk/libffm) - A library for Field-aware Factorization Machine (FFM). -* [lightfm](https://github.com/lyst/lightfm) - A Python implementation of a number of popular recommendation algorithms. -* [spotlight](https://github.com/maciejkula/spotlight) - Deep recommender models using PyTorch. -* [Surprise](https://github.com/NicolasHug/Surprise) - A scikit for building and analyzing recommender systems. -* [tensorrec](https://github.com/jfkirk/tensorrec) - A Recommendation Engine Framework in TensorFlow. +- [annoy](https://github.com/spotify/annoy) - Approximate Nearest Neighbors in C++/Python optimized for memory usage. +- [fastFM](https://github.com/ibayer/fastFM) - A library for Factorization Machines. +- [implicit](https://github.com/benfred/implicit) - A fast Python implementation of collaborative filtering for implicit datasets. +- [lightfm](https://github.com/lyst/lightfm) - A Python implementation of a number of popular recommendation algorithms. +- [spotlight](https://github.com/maciejkula/spotlight) - Deep recommender models using PyTorch. +- [scikit-surprise](https://github.com/NicolasHug/Surprise) - A scikit for building and analyzing recommender systems. +- [tensorrec](https://github.com/jfkirk/tensorrec) - A Recommendation Engine Framework in TensorFlow. + +## Refactoring + +_Refactoring tools and libraries for Python._ + +- [bowler](https://github.com/facebookincubator/Bowler) - Safe code refactoring for modern Python. +- [rope](https://github.com/python-rope/rope) - Rope is a python refactoring library. ## RESTful API -*Libraries for developing RESTful APIs.* - -* Django - * [django-rest-framework](http://www.django-rest-framework.org/) - A powerful and flexible toolkit to build web APIs. - * [django-tastypie](http://tastypieapi.org/) - Creating delicious APIs for Django apps. -* Flask - * [eve](https://github.com/pyeve/eve) - REST API framework powered by Flask, MongoDB and good intentions. - * [flask-api-utils](https://github.com/marselester/flask-api-utils) - Taking care of API representation and authentication for Flask. - * [flask-api](http://www.flaskapi.org/) - Browsable Web APIs for Flask. - * [flask-restful](https://github.com/flask-restful/flask-restful) - Quickly building REST APIs for Flask. - * [flask-restless](https://github.com/jfinkels/flask-restless) - Generating RESTful APIs for database models defined with SQLAlchemy. -* Pyramid - * [cornice](https://github.com/Cornices/cornice) - A RESTful framework for Pyramid. -* Framework agnostic - * [apistar](https://github.com/encode/apistar) - A smart Web API framework, designed for Python 3. - * [falcon](http://falconframework.org/) - A high-performance framework for building cloud APIs and web app backends. - * [hug](https://github.com/timothycrosley/hug) - A Python3 framework for cleanly exposing APIs over HTTP and the Command Line with automatic documentation and validation. - * [restless](https://github.com/toastdriven/restless) - Framework agnostic REST framework based on lessons learned from Tastypie. - * [ripozo](https://github.com/vertical-knowledge/ripozo) - Quickly creating REST/HATEOAS/Hypermedia APIs. - * [sandman](https://github.com/jeffknupp/sandman) - Automated REST APIs for existing database-driven systems. +_Libraries for building RESTful APIs._ + +- Django + - [django-rest-framework](https://github.com/encode/django-rest-framework) - A powerful and flexible toolkit to build web APIs. + - [django-tastypie](https://github.com/django-tastypie/django-tastypie) - Creating delicious APIs for Django apps. +- Flask + - [eve](https://github.com/pyeve/eve) - REST API framework powered by Flask, MongoDB and good intentions. + - [flask-api](https://github.com/flask-api/flask-api) - Browsable Web APIs for Flask. + - [flask-restful](https://github.com/flask-restful/flask-restful) - Quickly building REST APIs for Flask. +- Pyramid + - [cornice](https://github.com/Cornices/cornice) - A RESTful framework for Pyramid. +- Framework agnostic + - [falcon](https://github.com/falconry/falcon) - A high-performance framework for building cloud APIs and web app backends. + - [fastapi](https://github.com/tiangolo/fastapi) - A modern, fast, web framework for building APIs with Python 3.6+ based on standard Python type hints. + - [hug](https://github.com/hugapi/hug) - A Python 3 framework for cleanly exposing APIs. + - [sandman2](https://github.com/jeffknupp/sandman2) - Automated REST APIs for existing database-driven systems. + - [sanic](https://github.com/sanic-org/sanic) - A Python 3.6+ web server and web framework that's written to go fast. ## Robotics -*Libraries for robotics.* +_Libraries for robotics._ -* [PythonRobotics](https://github.com/AtsushiSakai/PythonRobotics) - This is a compilation of various robotics algorithms with visualizations. -* [rospy](http://wiki.ros.org/rospy) - This is a library for ROS (Robot Operating System). +- [PythonRobotics](https://github.com/AtsushiSakai/PythonRobotics) - This is a compilation of various robotics algorithms with visualizations. ## RPC Servers -*RPC-compatible servers.* +_RPC-compatible servers._ -* [SimpleJSONRPCServer](https://github.com/joshmarshall/jsonrpclib/) - This library is an implementation of the JSON-RPC specification. -* [SimpleXMLRPCServer](https://docs.python.org/3/library/xmlrpc.server.html) - (Python standard library) Simple XML-RPC server implementation, single-threaded. -* [zeroRPC](https://github.com/0rpc/zerorpc-python) - zerorpc is a flexible RPC implementation based on [ZeroMQ](http://zeromq.org/) and [MessagePack](http://msgpack.org/). +- [rpyc](https://github.com/tomerfiliba/rpyc) (Remote Python Call) - A transparent and symmetric RPC library for Python +- [zerorpc](https://github.com/0rpc/zerorpc-python) - zerorpc is a flexible RPC implementation based on [ZeroMQ](http://zeromq.org/) and [MessagePack](http://msgpack.org/). ## Science -*Libraries for scientific computing.* - -* [astropy](http://www.astropy.org/) - A community Python library for Astronomy. -* [bcbio-nextgen](https://github.com/chapmanb/bcbio-nextgen) - Providing best-practice pipelines for fully automated high throughput sequencing analysis. -* [bccb](https://github.com/chapmanb/bcbb) - Collection of useful code related to biological analysis. -* [Biopython](http://biopython.org/wiki/Main_Page) - Biopython is a set of freely available tools for biological computation. -* [cclib](http://cclib.github.io/) - A library for parsing and interpreting the results of computational chemistry packages. -* [Colour](http://colour-science.org/) - A colour science package implementing a comprehensive number of colour theory transformations and algorithms. -* [NetworkX](https://networkx.github.io/) - A high-productivity software for complex networks. -* [NIPY](http://nipy.org) - A collection of neuroimaging toolkits. -* [NumPy](http://www.numpy.org/) - A fundamental package for scientific computing with Python. -* [Open Babel](http://openbabel.org/wiki/Main_Page) - A chemical toolbox designed to speak the many languages of chemical data. -* [ObsPy](https://github.com/obspy/obspy/wiki/) - A Python toolbox for seismology. -* [PyDy](http://www.pydy.org/) - Short for Python Dynamics, used to assist with workflow in the modeling of dynamic motion. -* [PyMC](https://github.com/pymc-devs/pymc3) - Markov Chain Monte Carlo sampling toolkit. -* [QuTiP](http://qutip.org/) - Quantum Toolbox in Python. -* [RDKit](http://www.rdkit.org/) - Cheminformatics and Machine Learning Software. -* [SciPy](https://www.scipy.org/) - A Python-based ecosystem of open-source software for mathematics, science, and engineering. -* [statsmodels](https://github.com/statsmodels/statsmodels) - Statistical modeling and econometrics in Python. -* [SymPy](https://github.com/sympy/sympy) - A Python library for symbolic mathematics. -* [Zipline](https://github.com/quantopian/zipline) - A Pythonic algorithmic trading library. -* [SimPy](https://bitbucket.org/simpy/simpy) - A process-based discrete-event simulation framework. +_Libraries for scientific computing. Also see [Python-for-Scientists](https://github.com/TomNicholas/Python-for-Scientists)._ + +- [astropy](https://github.com/astropy/astropy) - A community Python library for Astronomy. +- [bcbb](https://github.com/chapmanb/bcbb) - Collection of useful code related to biological analysis. +- [biopython](https://github.com/biopython/biopython) - Biopython is a set of freely available tools for biological computation. +- [cclib](https://github.com/cclib/cclib) - A library for parsing and interpreting the results of computational chemistry packages. +- [colour](https://github.com/colour-science/colour) - Implementing a comprehensive number of colour theory transformations and algorithms. +- [karateclub](https://github.com/benedekrozemberczki/karateclub) - Unsupervised machine learning toolbox for graph structured data. +- [manim](https://github.com/ManimCommunity/manim) - An animation engine for explanatory math videos. +- [networkx](https://github.com/networkx/networkx) - A high-productivity software for complex networks. +- [nipy](https://github.com/nipy/nipy) - A collection of neuroimaging toolkits. +- [numpy](https://github.com/numpy/numpy) - A fundamental package for scientific computing with Python. +- [obspy](https://github.com/obspy/obspy) - A Python toolbox for seismology. +- [openbabel](https://github.com/openbabel/openbabel) - A chemical toolbox designed to speak the many languages of chemical data. +- [pathsim](https://github.com/pathsim/pathsim) - A block-based system modeling and simulation framework with a browser-based visual editor. +- [pydy](https://github.com/pydy/pydy) - Short for Python Dynamics, used to assist with workflow in the modeling of dynamic motion. +- [pymc](https://github.com/pymc-devs/pymc3) - Markov Chain Monte Carlo sampling toolkit. +- [rdkit](https://github.com/rdkit/rdkit) - Cheminformatics and Machine Learning Software. +- [scipy](https://github.com/scipy/scipy) - A Python-based ecosystem of open-source software for mathematics, science, and engineering. +- [shapely](https://github.com/shapely/shapely) - Manipulation and analysis of geometric objects in the Cartesian plane. +- [simpy](https://gitlab.com/team-simpy/simpy) - A process-based discrete-event simulation framework. +- [statsmodels](https://github.com/statsmodels/statsmodels) - Statistical modeling and econometrics in Python. +- [sympy](https://github.com/sympy/sympy) - A Python library for symbolic mathematics. ## Search -*Libraries and software for indexing and performing search queries on data.* +_Libraries and software for indexing and performing search queries on data._ -* [elasticsearch-py](https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/index.html) - The official low-level Python client for [Elasticsearch](https://www.elastic.co/products/elasticsearch). -* [elasticsearch-dsl-py](https://github.com/elastic/elasticsearch-dsl-py) - The official high-level Python client for Elasticsearch. -* [django-haystack](https://github.com/django-haystack/django-haystack) - Modular search for Django. -* [pysolr](https://github.com/django-haystack/pysolr) - A lightweight Python wrapper for [Apache Solr](https://lucene.apache.org/solr/). -* [whoosh](http://whoosh.readthedocs.io/en/latest/) - A fast, pure Python search engine library. +- [django-haystack](https://github.com/django-haystack/django-haystack) - Modular search for Django. +- [elasticsearch-dsl-py](https://github.com/elastic/elasticsearch-dsl-py) - The official high-level Python client for Elasticsearch. +- [elasticsearch-py](https://github.com/elastic/elasticsearch-py) - The official low-level Python client for [Elasticsearch](https://www.elastic.co/products/elasticsearch). +- [pysolr](https://github.com/django-haystack/pysolr) - A lightweight Python wrapper for [Apache Solr](https://lucene.apache.org/solr/). +- [whoosh](https://github.com/mchaput/whoosh) - A fast, pure Python search engine library. ## Serialization -*Libraries for serializing complex data types* +_Libraries for serializing complex data types._ -* [marshmallow](https://github.com/marshmallow-code/marshmallow) - A lightweight library for converting complex objects to and from simple Python datatypes. -* [pysimdjson](https://github.com/TkTech/pysimdjson) - A Python bindings for [simdjson](https://github.com/lemire/simdjson). -* [python-rapidjson](https://github.com/python-rapidjson/python-rapidjson) - A Python wrapper around [RapidJSON](https://github.com/Tencent/rapidjson). +- [marshmallow](https://github.com/marshmallow-code/marshmallow) - A lightweight library for converting complex objects to and from simple Python datatypes. +- [orjson](https://github.com/ijl/orjson) - Fast, correct JSON library. +- [pysimdjson](https://github.com/TkTech/pysimdjson) - A Python bindings for [simdjson](https://github.com/lemire/simdjson). +- [python-rapidjson](https://github.com/python-rapidjson/python-rapidjson) - A Python wrapper around [RapidJSON](https://github.com/Tencent/rapidjson). +- [toonify](https://github.com/ScrapeGraphAI/toonify) - A compact, human-readable serialization format that reduces LLM token usage by 30-60% compared to JSON. +- [ultrajson](https://github.com/esnme/ultrajson) - A fast JSON decoder and encoder written in C with Python bindings. ## Serverless Frameworks -*Frameworks for developing serverless Python code.* +_Frameworks for developing serverless Python code._ + +- [python-lambda](https://github.com/nficano/python-lambda) - A toolkit for developing and deploying Python code in AWS Lambda. +- [zappa](https://github.com/zappa/Zappa) - A tool for deploying WSGI applications on AWS Lambda and API Gateway. -* [python-lambda](https://github.com/nficano/python-lambda) - A toolkit for developing and deploying Python code in AWS Lambda. -* [Zappa](https://github.com/Miserlou/Zappa) - A tool for deploying WSGI applications on AWS Lambda and API Gateway. +## Shell + +_Shells built with Python._ + +- [xonsh](https://github.com/xonsh/xonsh/) - A Python-powered shell. Full-featured and cross-platform. ## Specific Formats Processing -*Libraries for parsing and manipulating specific text formats.* - -* General - * [tablib](https://github.com/kennethreitz/tablib) - A module for Tabular Datasets in XLS, CSV, JSON, YAML. -* Office - * [openpyxl](https://openpyxl.readthedocs.io/en/stable/) - A library for reading and writing Excel 2010 xlsx/xlsm/xltx/xltm files. - * [pyexcel](https://github.com/pyexcel/pyexcel) - Providing one API for reading, manipulating and writing csv, ods, xls, xlsx and xlsm files. - * [python-docx](https://github.com/python-openxml/python-docx) - Reads, queries and modifies Microsoft Word 2007/2008 docx files. - * [python-pptx](https://github.com/scanny/python-pptx) - Python library for creating and updating PowerPoint (.pptx) files. - * [unoconv](https://github.com/unoconv/unoconv) - Convert between any document format supported by LibreOffice/OpenOffice. - * [XlsxWriter](https://github.com/jmcnamara/XlsxWriter) - A Python module for creating Excel .xlsx files. - * [xlwings](https://github.com/ZoomerAnalytics/xlwings) - A BSD-licensed library that makes it easy to call Python from Excel and vice versa. - * [xlwt](https://github.com/python-excel/xlwt) / [xlrd](https://github.com/python-excel/xlrd) - Writing and reading data and formatting information from Excel files. -* PDF - * [PDFMiner](https://github.com/euske/pdfminer) - A tool for extracting information from PDF documents. - * [PyPDF2](https://github.com/mstamy2/PyPDF2) - A library capable of splitting, merging and transforming PDF pages. - * [ReportLab](https://www.reportlab.com/opensource/) - Allowing Rapid creation of rich PDF documents. -* Markdown - * [Mistune](https://github.com/lepture/mistune) - Fastest and full featured pure Python parsers of Markdown. - * [Python-Markdown](https://github.com/waylan/Python-Markdown) - A Python implementation of John Gruber’s Markdown. -* YAML - * [PyYAML](http://pyyaml.org/) - YAML implementations for Python. -* CSV - * [csvkit](https://github.com/wireservice/csvkit) - Utilities for converting to and working with CSV. -* Archive - * [unp](https://github.com/mitsuhiko/unp) - A command line tool that can unpack archives easily. +_Libraries for parsing and manipulating specific text formats._ + +- General + - [docling](https://github.com/docling-project/docling) - Library for converting documents into structured data. + - [kreuzberg](https://github.com/kreuzberg-dev/kreuzberg) - High-performance document extraction library with a Rust core, supporting 62+ formats including PDF, Office, images with OCR, HTML, email, and archives. + - [tablib](https://github.com/jazzband/tablib) - A module for Tabular Datasets in XLS, CSV, JSON, YAML. + - [textract](https://github.com/deanmalmgren/textract) - Extract text from any document, Word, PowerPoint, PDFs, etc. +- Office + - [docxtpl](https://github.com/elapouya/python-docx-template) - Editing a docx document by jinja2 template + - [openpyxl](https://openpyxl.readthedocs.io/en/stable/) - A library for reading and writing Excel 2010 xlsx/xlsm/xltx/xltm files. + - [pyexcel](https://github.com/pyexcel/pyexcel) - Providing one API for reading, manipulating and writing csv, ods, xls, xlsx and xlsm files. + - [python-docx](https://github.com/python-openxml/python-docx) - Reads, queries and modifies Microsoft Word 2007/2008 docx files. + - [python-pptx](https://github.com/scanny/python-pptx) - Python library for creating and updating PowerPoint (.pptx) files. + - [xlsxwriter](https://github.com/jmcnamara/XlsxWriter) - A Python module for creating Excel .xlsx files. + - [xlwings](https://github.com/ZoomerAnalytics/xlwings) - A BSD-licensed library that makes it easy to call Python from Excel and vice versa. +- PDF + - [pdf_oxide](https://github.com/yfedoseev/pdf_oxide) - A fast PDF library for text extraction, image extraction, and markdown conversion, powered by Rust. + - [pdfminer.six](https://github.com/pdfminer/pdfminer.six) - Pdfminer.six is a community maintained fork of the original PDFMiner. + - [pikepdf](https://github.com/pikepdf/pikepdf) - A powerful library for reading and editing PDF files, based on qpdf. + - [PyPDF2](https://github.com/mstamy2/PyPDF2) - A library capable of splitting, merging and transforming PDF pages. + - [reportlab](https://www.reportlab.com/opensource/) - Allowing Rapid creation of rich PDF documents. +- Markdown + - [markdown-it-py](https://github.com/executablebooks/markdown-it-py) - Markdown parser with 100% CommonMark support, extensions, and syntax plugins. + - [markdown](https://github.com/waylan/Python-Markdown) - A Python implementation of John Gruber’s Markdown. + - [markitdown](https://github.com/microsoft/markitdown) - Python tool for converting files and office documents to Markdown. + - [mistune](https://github.com/lepture/mistune) - Fastest and full featured pure Python parsers of Markdown. +- YAML + - [pyyaml](https://github.com/yaml/pyyaml) - YAML implementations for Python. +- TOML + - [tomllib](https://docs.python.org/3/library/tomllib.html) - (Python standard library) Parse TOML files. +- CSV + - [csvkit](https://github.com/wireservice/csvkit) - Utilities for converting to and working with CSV. +- Archive + - [unp](https://github.com/mitsuhiko/unp) - A command line tool that can unpack archives easily. ## Static Site Generator -*Static site generator is a software that takes some text + templates as input and produces HTML files on the output.* +_Static site generator is a software that takes some text + templates as input and produces HTML files on the output._ -* [mkdocs](https://github.com/mkdocs/mkdocs/) - Markdown friendly documentation generator. -* [pelican](https://github.com/getpelican/pelican) - Static site generator that supports Markdown and reST syntax. -* [lektor](https://github.com/lektor/lektor) - An easy to use static CMS and blog engine. -* [nikola](https://github.com/getnikola/nikola) - A static website and blog generator. +- [lektor](https://github.com/lektor/lektor) - An easy to use static CMS and blog engine. +- [makesite](https://github.com/sunainapai/makesite) - Simple, lightweight, and magic-free static site/blog generator (< 130 lines). +- [mkdocs](https://github.com/mkdocs/mkdocs/) - Markdown friendly documentation generator. +- [nikola](https://github.com/getnikola/nikola) - A static website and blog generator. +- [pelican](https://github.com/getpelican/pelican) - Static site generator that supports Markdown and reST syntax. -## Tagging +## Task Queues -*Libraries for tagging items.* +_Libraries for working with task queues._ -* [django-taggit](https://github.com/jazzband/django-taggit) - Simple tagging for Django. +- [celery](https://github.com/celery/celery) - An asynchronous task queue/job queue based on distributed message passing. +- [dramatiq](https://github.com/Bogdanp/dramatiq) - A fast and reliable background task processing library for Python 3. +- [huey](https://github.com/coleifer/huey) - Little multi-threaded task queue. +- [mrq](https://github.com/pricingassistant/mrq) - A distributed worker task queue in Python using Redis & gevent. +- [rq](https://github.com/rq/rq) - Simple job queues for Python. ## Template Engine -*Libraries and tools for templating and lexing.* +_Libraries and tools for templating and lexing._ -* [Jinja2](https://github.com/pallets/jinja) - A modern and designer friendly templating language. -* [Genshi](https://genshi.edgewall.org/) - Python templating toolkit for generation of web-aware output. -* [Mako](http://www.makotemplates.org/) - Hyperfast and lightweight templating for the Python platform. +- [genshi](https://github.com/edgewall/genshi) - Python templating toolkit for generation of web-aware output. +- [jinja](https://github.com/pallets/jinja) - A modern and designer friendly templating language. +- [mako](https://github.com/sqlalchemy/mako) - Hyperfast and lightweight templating for the Python platform. ## Testing -*Libraries for testing codebases and generating test data.* - -* Testing Frameworks - * [pytest](https://docs.pytest.org/en/latest/) - A mature full-featured Python testing tool. - * [hypothesis](https://github.com/HypothesisWorks/hypothesis) - Hypothesis is an advanced Quickcheck style property based testing library. - * [nose2](https://github.com/nose-devs/nose2) - The successor to `nose`, based on `unittest2. - * [Robot Framework](https://github.com/robotframework/robotframework) - A generic test automation framework. - * [unittest](https://docs.python.org/3/library/unittest.html) - (Python standard library) Unit testing framework. -* Test Runners - * [green](https://github.com/CleanCut/green) - A clean, colorful test runner. - * [mamba](http://nestorsalceda.github.io/mamba/) - The definitive testing tool for Python. Born under the banner of BDD. - * [tox](https://tox.readthedocs.io/en/latest/) - Auto builds and tests distributions in multiple Python versions -* GUI / Web Testing - * [locust](https://github.com/locustio/locust) - Scalable user load testing tool written in Python. - * [PyAutoGUI](https://github.com/asweigart/pyautogui) - PyAutoGUI is a cross-platform GUI automation Python module for human beings. - * [Selenium](https://pypi.python.org/pypi/selenium) - Python bindings for [Selenium](http://www.seleniumhq.org/) WebDriver. - * [sixpack](https://github.com/seatgeek/sixpack) - A language-agnostic A/B Testing framework. - * [splinter](https://github.com/cobrateam/splinter) - Open source tool for testing web applications. -* Mock - * [doublex](https://pypi.python.org/pypi/doublex) - Powerful test doubles framework for Python. - * [freezegun](https://github.com/spulec/freezegun) - Travel through time by mocking the datetime module. - * [httmock](https://github.com/patrys/httmock) - A mocking library for requests for Python 2.6+ and 3.2+. - * [httpretty](https://github.com/gabrielfalcao/HTTPretty) - HTTP request mock tool for Python. - * [mock](https://docs.python.org/3/library/unittest.mock.html) - (Python standard library) A mocking and patching library. - * [Mocket](https://github.com/mindflayer/python-mocket) - Socket Mock Framework plus HTTP[S]/asyncio/gevent mocking library with recording/replaying capability. - * [responses](https://github.com/getsentry/responses) - A utility library for mocking out the requests Python library. - * [VCR.py](https://github.com/kevin1024/vcrpy) - Record and replay HTTP interactions on your tests. -* Object Factories - * [factory_boy](https://github.com/FactoryBoy/factory_boy) - A test fixtures replacement for Python. - * [mixer](https://github.com/klen/mixer) - Another fixtures replacement. Supported Django, Flask, SQLAlchemy, Peewee and etc. - * [model_mommy](https://github.com/vandersonmota/model_mommy) - Creating random fixtures for testing in Django. -* Code Coverage - * [coverage](https://pypi.python.org/pypi/coverage) - Code coverage measurement. -* Fake Data - * [mimesis](https://github.com/lk-geimfari/mimesis) - is a Python library that help you generate fake data. - * [fake2db](https://github.com/emirozer/fake2db) - Fake database generator. - * [faker](https://github.com/joke2k/faker) - A Python package that generates fake data. - * [radar](https://pypi.python.org/pypi/radar) - Generate random datetime / time. -* Error Handler - * [FuckIt.py](https://github.com/ajalt/fuckitpy) - FuckIt.py uses state-of-the-art technology to make sure your Python code runs whether it has any right to or not. +_Libraries for testing codebases and generating test data._ + +- Testing Frameworks + - [hypothesis](https://github.com/HypothesisWorks/hypothesis) - Hypothesis is an advanced Quickcheck style property based testing library. + - [nose2](https://github.com/nose-devs/nose2) - The successor to `nose`, based on `unittest2`. + - [pytest](https://github.com/pytest-dev/pytest) - A mature full-featured Python testing tool. + - [robotframework](https://github.com/robotframework/robotframework) - A generic test automation framework. + - [scanapi](https://github.com/scanapi/scanapi) - Automated Testing and Documentation for your REST API. + - [unittest](https://docs.python.org/3/library/unittest.html) - (Python standard library) Unit testing framework. +- Test Runners + - [green](https://github.com/CleanCut/green) - A clean, colorful test runner. + - [mamba](https://github.com/nestorsalceda/mamba) - The definitive testing tool for Python. Born under the banner of BDD. + - [tox](https://github.com/tox-dev/tox) - Auto builds and tests distributions in multiple Python versions +- GUI / Web Testing + - [locust](https://github.com/locustio/locust) - Scalable user load testing tool written in Python. + - [pyautogui](https://github.com/asweigart/pyautogui) - PyAutoGUI is a cross-platform GUI automation Python module for human beings. + - [schemathesis](https://github.com/kiwicom/schemathesis) - A tool for automatic property-based testing of web applications built with Open API / Swagger specifications. + - [selenium](https://github.com/SeleniumHQ/selenium) - Python bindings for [Selenium](https://selenium.dev/) [WebDriver](https://selenium.dev/documentation/webdriver/). + - [splinter](https://github.com/cobrateam/splinter) - Open source tool for testing web applications. +- Mock + - [doublex](https://pypi.org/project/doublex/) - Powerful test doubles framework for Python. + - [freezegun](https://github.com/spulec/freezegun) - Travel through time by mocking the datetime module. + - [httmock](https://github.com/patrys/httmock) - A mocking library for requests for Python 2.6+ and 3.2+. + - [httpretty](https://github.com/gabrielfalcao/HTTPretty) - HTTP request mock tool for Python. + - [mock](https://docs.python.org/3/library/unittest.mock.html) - (Python standard library) A mocking and patching library. + - [mocket](https://github.com/mindflayer/python-mocket) - A socket mock framework with gevent/asyncio/SSL support. + - [responses](https://github.com/getsentry/responses) - A utility library for mocking out the requests Python library. + - [vcrpy](https://github.com/kevin1024/vcrpy) - Record and replay HTTP interactions on your tests. +- Object Factories + - [factory_boy](https://github.com/FactoryBoy/factory_boy) - A test fixtures replacement for Python. + - [mixer](https://github.com/klen/mixer) - Another fixtures replacement. Supports Django, Flask, SQLAlchemy, Peewee and etc. + - [polyfactory](https://github.com/litestar-org/polyfactory) - mock data generation library with support to classes (continuation of `pydantic-factories`) +- Code Coverage + - [coverage](https://github.com/coveragepy/coveragepy) - Code coverage measurement. +- Fake Data + - [faker](https://github.com/joke2k/faker) - A Python package that generates fake data. + - [mimesis](https://github.com/lk-geimfari/mimesis) - is a Python library that help you generate fake data. ## Text Processing -*Libraries for parsing and manipulating plain texts.* - -* General - * [chardet](https://github.com/chardet/chardet) - Python 2/3 compatible character encoding detector. - * [difflib](https://docs.python.org/3/library/difflib.html) - (Python standard library) Helpers for computing deltas. - * [ftfy](https://github.com/LuminosoInsight/python-ftfy) - Makes Unicode text less broken and more consistent automagically. - * [fuzzywuzzy](https://github.com/seatgeek/fuzzywuzzy) - Fuzzy String Matching. - * [Levenshtein](https://github.com/ztane/python-Levenshtein/) - Fast computation of Levenshtein distance and string similarity. - * [pangu.py](https://github.com/vinta/pangu.py) - Paranoid text spacing. - * [pyfiglet](https://github.com/pwaller/pyfiglet) - An implementation of figlet written in Python. - * [pypinyin](https://github.com/mozillazg/python-pinyin) - Convert Chinese hanzi (漢字) to pinyin (拼音). - * [textdistance](https://github.com/orsinium/textdistance) - Compute distance between sequences. 30+ algorithms, pure python implementation, common interface, optional external libs usage. - * [unidecode](https://pypi.python.org/pypi/Unidecode) - ASCII transliterations of Unicode text. -* Slugify - * [awesome-slugify](https://github.com/dimka665/awesome-slugify) - A Python slugify library that can preserve unicode. - * [python-slugify](https://github.com/un33k/python-slugify) - A Python slugify library that translates unicode to ASCII. - * [unicode-slugify](https://github.com/mozilla/unicode-slugify) - A slugifier that generates unicode slugs with Django as a dependency. -* Unique identifiers - * [hashids](https://github.com/davidaurelio/hashids-python) - Implementation of [hashids](http://hashids.org) in Python. - * [shortuuid](https://github.com/skorokithakis/shortuuid) - A generator library for concise, unambiguous and URL-safe UUIDs. -* Parser - * [ply](https://github.com/dabeaz/ply) - Implementation of lex and yacc parsing tools for Python. - * [pygments](http://pygments.org/) - A generic syntax highlighter. - * [pyparsing](https://github.com/pyparsing/pyparsing) - A general purpose framework for generating parsers. - * [python-nameparser](https://github.com/derek73/python-nameparser) - Parsing human names into their individual components. - * [python-phonenumbers](https://github.com/daviddrysdale/python-phonenumbers) - Parsing, formatting, storing and validating international phone numbers. - * [python-user-agents](https://github.com/selwin/python-user-agents) - Browser user agent parser. - * [sqlparse](https://github.com/andialbrecht/sqlparse) - A non-validating SQL parser. - -## Third-party APIs - -*Libraries for accessing third party services APIs. See: [List of Python API Wrappers and Libraries](https://github.com/realpython/list-of-python-api-wrappers).* - -* [apache-libcloud](https://libcloud.apache.org/) - One Python library for all clouds. -* [boto3](https://github.com/boto/boto3) - Python interface to Amazon Web Services. -* [django-wordpress](https://github.com/istrategylabs/django-wordpress) - WordPress models and views for Django. -* [facebook-sdk](https://github.com/mobolic/facebook-sdk) - Facebook Platform Python SDK. -* [google-api-python-client](https://github.com/google/google-api-python-client) - Google APIs Client Library for Python. -* [gspread](https://github.com/burnash/gspread) - Google Spreadsheets Python API. -* [twython](https://github.com/ryanmcgrath/twython) - A Python wrapper for the Twitter API. +_Libraries for parsing and manipulating plain texts._ + +- General + - [chardet](https://github.com/chardet/chardet) - Python 2/3 compatible character encoding detector. + - [difflib](https://docs.python.org/3/library/difflib.html) - (Python standard library) Helpers for computing deltas. + - [ftfy](https://github.com/LuminosoInsight/python-ftfy) - Makes Unicode text less broken and more consistent automagically. + - [Levenshtein](https://github.com/ztane/python-Levenshtein/) - Fast computation of Levenshtein distance and string similarity. + - [pangu.py](https://github.com/vinta/pangu.py) - Paranoid text spacing. + - [pyfiglet](https://github.com/pwaller/pyfiglet) - An implementation of figlet written in Python. + - [pypinyin](https://github.com/mozillazg/python-pinyin) - Convert Chinese hanzi (漢字) to pinyin (拼音). + - [textdistance](https://github.com/orsinium/textdistance) - Compute distance between sequences with 30+ algorithms. + - [unidecode](https://github.com/avian2/unidecode) - ASCII transliterations of Unicode text. +- Slugify + - [awesome-slugify](https://github.com/dimka665/awesome-slugify) - A Python slugify library that can preserve unicode. + - [python-slugify](https://github.com/un33k/python-slugify) - A Python slugify library that translates unicode to ASCII. + - [unicode-slugify](https://github.com/mozilla/unicode-slugify) - A slugifier that generates unicode slugs with Django as a dependency. +- Unique identifiers + - [hashids](https://github.com/davidaurelio/hashids-python) - Implementation of [hashids](http://hashids.org) in Python. + - [shortuuid](https://github.com/skorokithakis/shortuuid) - A generator library for concise, unambiguous and URL-safe UUIDs. +- Parser + - [pygments](https://github.com/pygments/pygments) - A generic syntax highlighter. + - [pyparsing](https://github.com/pyparsing/pyparsing) - A general purpose framework for generating parsers. + - [python-nameparser](https://github.com/derek73/python-nameparser) - Parsing human names into their individual components. + - [python-phonenumbers](https://github.com/daviddrysdale/python-phonenumbers) - Parsing, formatting, storing and validating international phone numbers. + - [python-user-agents](https://github.com/selwin/python-user-agents) - Browser user agent parser. + - [sqlparse](https://github.com/andialbrecht/sqlparse) - A non-validating SQL parser. ## URL Manipulation -*Libraries for parsing URLs.* +_Libraries for parsing URLs._ -* [furl](https://github.com/gruns/furl) - A small Python library that makes parsing and manipulating URLs easy. -* [purl](https://github.com/codeinthehole/purl) - A simple, immutable URL class with a clean API for interrogation and manipulation. -* [pyshorteners](https://github.com/ellisonleao/pyshorteners) - A pure Python URL shortening lib. -* [webargs](https://github.com/marshmallow-code/webargs) - A friendly library for parsing HTTP request arguments, with built-in support for popular web frameworks, including Flask, Django, Bottle, Tornado, and Pyramid. +- [furl](https://github.com/gruns/furl) - A small Python library that makes parsing and manipulating URLs easy. +- [purl](https://github.com/codeinthehole/purl) - A simple, immutable URL class with a clean API for interrogation and manipulation. +- [webargs](https://github.com/marshmallow-code/webargs) - A friendly library for parsing HTTP request arguments with built-in support for popular web frameworks. ## Video -*Libraries for manipulating video and GIFs.* - -* [moviepy](https://zulko.github.io/moviepy/) - A module for script-based movie editing with many formats, including animated GIFs. -* [scikit-video](https://github.com/aizvorski/scikit-video) - Video processing routines for SciPy. +_Libraries for manipulating video and GIFs._ -## WSGI Servers - -*WSGI-compatible web servers.* - -* [bjoern](https://github.com/jonashaag/bjoern) - Asynchronous, very fast and written in C. -* [gunicorn](https://github.com/benoitc/gunicorn) - Pre-forked, partly written in C. -* [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) - A project aims at developing a full stack for building hosting services, written in C. -* [waitress](https://github.com/Pylons/waitress) - Multi-threaded, powers Pyramid. -* [werkzeug](https://github.com/pallets/werkzeug) - A WSGI utility library for Python that powers Flask and can easily be embedded into your own projects. +- [moviepy](https://github.com/Zulko/moviepy) - A module for script-based movie editing with many formats, including animated GIFs. +- [scikit-video](https://github.com/aizvorski/scikit-video) - Video processing routines for SciPy. +- [vidgear](https://github.com/abhiTronix/vidgear) - Most Powerful multi-threaded Video Processing framework. ## Web Asset Management -*Tools for managing, compressing and minifying website assets.* +_Tools for managing, compressing and minifying website assets._ -* [django-compressor](https://github.com/django-compressor/django-compressor) - Compresses linked and inline JavaScript or CSS into a single cached file. -* [django-pipeline](https://github.com/jazzband/django-pipeline) - An asset packaging library for Django. -* [django-storages](https://github.com/jschneier/django-storages) - A collection of custom storage back ends for Django. -* [fanstatic](http://www.fanstatic.org/en/latest/) - Packages, optimizes, and serves static file dependencies as Python packages. -* [fileconveyor](http://wimleers.com/fileconveyor) - A daemon to detect and sync files to CDNs, S3 and FTP. -* [flask-assets](https://github.com/miracle2k/flask-assets) - Helps you integrate webassets into your Flask app. -* [webassets](https://github.com/miracle2k/webassets) - Bundles, optimizes, and manages unique cache-busting URLs for static resources. +- [django-compressor](https://github.com/django-compressor/django-compressor) - Compresses linked and inline JavaScript or CSS into a single cached file. +- [django-pipeline](https://github.com/jazzband/django-pipeline) - An asset packaging library for Django. +- [django-storages](https://github.com/jschneier/django-storages) - A collection of custom storage back ends for Django. +- [fanstatic](https://github.com/zopefoundation/fanstatic) - Packages, optimizes, and serves static file dependencies as Python packages. +- [flask-assets](https://github.com/miracle2k/flask-assets) - Helps you integrate webassets into your Flask app. +- [webassets](https://github.com/miracle2k/webassets) - Bundles, optimizes, and manages unique cache-busting URLs for static resources. ## Web Content Extracting -*Libraries for extracting web contents.* +_Libraries for extracting web contents._ -* [html2text](https://github.com/Alir3z4/html2text) - Convert HTML to Markdown-formatted text. -* [lassie](https://github.com/michaelhelmick/lassie) - Web Content Retrieval for Humans. -* [micawber](https://github.com/coleifer/micawber) - A small library for extracting rich content from URLs. -* [newspaper](https://github.com/codelucas/newspaper) - News extraction, article extraction and content curation in Python. -* [python-readability](https://github.com/buriy/python-readability) - Fast Python port of arc90's readability tool. -* [requests-html](https://github.com/kennethreitz/requests-html) - Pythonic HTML Parsing for Humans. -* [sumy](https://github.com/miso-belica/sumy) - A module for automatic summarization of text documents and HTML pages. -* [textract](https://github.com/deanmalmgren/textract) - Extract text from any document, Word, PowerPoint, PDFs, etc. -* [toapi](https://github.com/gaojiuli/toapi) - Every web site provides APIs. +- [html2text](https://github.com/Alir3z4/html2text) - Convert HTML to Markdown-formatted text. +- [lassie](https://github.com/michaelhelmick/lassie) - Web Content Retrieval for Humans. +- [micawber](https://github.com/coleifer/micawber) - A small library for extracting rich content from URLs. +- [newspaper](https://github.com/codelucas/newspaper) - News extraction, article extraction and content curation in Python. +- [python-readability](https://github.com/buriy/python-readability) - Fast Python port of arc90's readability tool. +- [requests-html](https://github.com/psf/requests-html) - Pythonic HTML Parsing for Humans. +- [sumy](https://github.com/miso-belica/sumy) - A module for automatic summarization of text documents and HTML pages. +- [toapi](https://github.com/gaojiuli/toapi) - Every web site provides APIs. -## Web Crawling & Web Scraping +## Web Crawling -*Libraries to automate data extraction from websites.* +_Libraries to automate web scraping._ -* [cola](https://github.com/chineking/cola) - A distributed crawling framework. -* [feedparser](https://pythonhosted.org/feedparser/) - Universal feed parser. -* [grab](https://github.com/lorien/grab) - Site scraping framework. -* [MechanicalSoup](https://github.com/MechanicalSoup/MechanicalSoup) - A Python library for automating interaction with websites. -* [portia](https://github.com/scrapinghub/portia) - Visual scraping for Scrapy. -* [pyspider](https://github.com/binux/pyspider) - A powerful spider system. -* [robobrowser](https://github.com/jmcarp/robobrowser) - A simple, Pythonic library for browsing the web without a standalone web browser. -* [scrapy](https://scrapy.org/) - A fast high-level screen scraping and web crawling framework. +- [browser-use](https://github.com/browser-use/browser-use) - Make websites accessible for AI agents with easy browser automation. +- [crawl4ai](https://github.com/unclecode/crawl4ai) - An open-source, LLM-friendly web crawler that provides lightning-fast, structured data extraction specifically designed for AI agents. +- [feedparser](https://github.com/kurtmckee/feedparser) - Universal feed parser. +- [grab](https://github.com/lorien/grab) - Site scraping framework. +- [mechanicalsoup](https://github.com/MechanicalSoup/MechanicalSoup) - A Python library for automating interaction with websites. +- [scrapy](https://github.com/scrapy/scrapy) - A fast high-level screen scraping and web crawling framework. ## Web Frameworks -*Full stack web frameworks.* - -* [Django](https://www.djangoproject.com/) - The most popular web framework in Python. - * [awesome-django](https://github.com/shahraizali/awesome-django) -* [Flask](http://flask.pocoo.org/) - A microframework for Python. - * [awesome-flask](https://github.com/humiaozuzu/awesome-flask) -* [Pyramid](https://pylonsproject.org/) - A small, fast, down-to-earth, open source Python web framework. - * [awesome-pyramid](https://github.com/uralbash/awesome-pyramid) -* [Sanic](https://github.com/channelcat/sanic) - Web server that's written to go fast. -* [Vibora](https://vibora.io/) - Fast, efficient and asynchronous Web framework inspired by Flask. -* [Tornado](http://www.tornadoweb.org/en/latest/) - A Web framework and asynchronous networking library. +_Traditional full stack web frameworks. Also see [RESTful API](https://github.com/vinta/awesome-python#restful-api)._ + +- Synchronous + - [django](https://github.com/django/django) - The most popular web framework in Python. + - [awesome-django](https://github.com/shahraizali/awesome-django) + - [flask](https://github.com/pallets/flask) - A microframework for Python. + - [awesome-flask](https://github.com/humiaozuzu/awesome-flask) + - [pyramid](https://github.com/Pylons/pyramid) - A small, fast, down-to-earth, open source Python web framework. + - [awesome-pyramid](https://github.com/uralbash/awesome-pyramid) + - [fasthtml](https://github.com/AnswerDotAI/fasthtml) - The fastest way to create an HTML app. + - [awesome-fasthtml](https://github.com/amosgyamfi/awesome-fasthtml) + - [masonite](https://github.com/MasoniteFramework/masonite) - The modern and developer centric Python web framework. +- Asynchronous + - [litestar](https://github.com/litestar-org/litestar) - Production-ready, capable and extensible ASGI Web framework. + - [microdot](https://github.com/miguelgrinberg/microdot) - The impossibly small web framework for Python and MicroPython. + - [reflex](https://github.com/reflex-dev/reflex) – A framework for building reactive, full-stack web applications entirely with python . + - [tornado](https://github.com/tornadoweb/tornado) - A web framework and asynchronous networking library. ## WebSocket -*Libraries for working with WebSocket.* +_Libraries for working with WebSocket._ -* [autobahn-python](https://github.com/crossbario/autobahn-python) - WebSocket & WAMP for Python on Twisted and [asyncio](https://docs.python.org/3/library/asyncio.html). -* [crossbar](https://github.com/crossbario/crossbar/) - Open-source Unified Application Router (Websocket & WAMP for Python on Autobahn). -* [django-channels](https://github.com/django/channels) - Developer-friendly asynchrony for Django. -* [django-socketio](https://github.com/stephenmcd/django-socketio) - WebSockets for Django. -* [WebSocket-for-Python](https://github.com/Lawouach/WebSocket-for-Python) - WebSocket client and server library for Python 2 and 3 as well as PyPy. +- [autobahn-python](https://github.com/crossbario/autobahn-python) - WebSocket & WAMP for Python on Twisted and [asyncio](https://docs.python.org/3/library/asyncio.html). +- [channels](https://github.com/django/channels) - Developer-friendly asynchrony for Django. +- [websockets](https://github.com/aaugustin/websockets) - A library for building WebSocket servers and clients with a focus on correctness and simplicity. -# Services - -Online tools and APIs to simplify development. +## WSGI Servers -## Continuous Integration +_WSGI-compatible web servers._ -*See: [awesome-CIandCD](https://github.com/ciandcd/awesome-ciandcd#online-build-system).* +- [gunicorn](https://github.com/benoitc/gunicorn) - Pre-forked, ported from Ruby's Unicorn project. +- [uwsgi](https://github.com/unbit/uwsgi) - A project aims at developing a full stack for building hosting services, written in C. +- [waitress](https://github.com/Pylons/waitress) - Multi-threaded, powers Pyramid. +- [werkzeug](https://github.com/pallets/werkzeug) - A WSGI utility library for Python that powers Flask and can easily be embedded into your own projects. -* [CircleCI](https://circleci.com/) - A CI service that can run very fast parallel testing. (GitHub only) -* [Travis CI](https://travis-ci.org) - A popular CI service for your open source and [private](https://travis-ci.com) projects. (GitHub only) -* [Vexor CI](https://vexor.io) - A continuous integration tool for private apps with pay-per-minute billing model. -* [Wercker](http://www.wercker.com/) - A Docker-based platform for building and deploying applications and microservices. +# Resources -## Code Quality +Where to discover learning resources or new Python libraries. -* [Codacy](https://www.codacy.com/) - Automated Code Review to ship better code, faster. -* [Codecov](https://codecov.io/) - Code coverage dashboard. -* [CodeFactor](https://www.codefactor.io/) - Automated Code Review for Git. -* [Landscape](https://landscape.io/) - Hosted continuous Python code metrics. +## Newsletters -# Resources - -Where to discover new Python libraries. +- [Awesome Python Newsletter](http://python.libhunt.com/newsletter) +- [Pycoder's Weekly](https://pycoders.com/) +- [Python Tricks](https://realpython.com/python-tricks/) +- [Python Weekly](https://www.pythonweekly.com/) ## Podcasts -* [From Python Import Podcast](http://frompythonimportpodcast.com/) -* [Podcast.init](https://podcastinit.com/) -* [Python Bytes](https://pythonbytes.fm) -* [Python Testing](http://pythontesting.net) -* [Radio Free Python](http://radiofreepython.com/) -* [Talk Python To Me](https://talkpython.fm/) - -## Twitter - -* [@codetengu](https://twitter.com/codetengu) -* [@getpy](https://twitter.com/getpy) -* [@importpython](https://twitter.com/importpython) -* [@planetpython](https://twitter.com/planetpython) -* [@pycoders](https://twitter.com/pycoders) -* [@pypi](https://twitter.com/pypi) -* [@pythontrending](https://twitter.com/pythontrending) -* [@PythonWeekly](https://twitter.com/PythonWeekly) -* [@TalkPython](https://twitter.com/talkpython) -* [@realpython](https://twitter.com/realpython) - -## Websites - -* [/r/CoolGithubProjects](https://www.reddit.com/r/coolgithubprojects/) -* [/r/Python](https://www.reddit.com/r/python) -* [Awesome Python @LibHunt](https://python.libhunt.com/) -* [Django Packages](https://djangopackages.org/) -* [Full Stack Python](https://www.fullstackpython.com/) -* [PyPI Ranking](http://pypi-ranking.info/alltime) -* [Python 3 Wall of Superpowers](http://python3wos.appspot.com/) -* [Python Hackers](http://www.oss.io/open-source/) -* [Python ZEEF](https://python.zeef.com/alan.richmond) -* [Python 开发社区](https://www.ctolib.com/python/) -* [Real Python](https://realpython.com) -* [Trending Python repositories on GitHub today](https://github.com/trending?l=python) - -## Weekly - -* [CodeTengu Weekly 碼天狗週刊](https://weekly.codetengu.com/) -* [Import Python Newsletter](http://importpython.com/newsletter/) -* [Pycoder's Weekly](http://pycoders.com/) -* [Python Weekly](http://www.pythonweekly.com/) -* [Python Tricks](https://realpython.com/python-tricks/) +- [Django Chat](https://djangochat.com/) +- [PyPodcats](https://pypodcats.live) +- [Python Bytes](https://pythonbytes.fm) +- [Python Test](https://podcast.pythontest.com/) +- [Talk Python To Me](https://talkpython.fm/) +- [The Real Python Podcast](https://realpython.com/podcasts/rpp/) # Contributing Your contributions are always welcome! Please take a look at the [contribution guidelines](https://github.com/vinta/awesome-python/blob/master/CONTRIBUTING.md) first. -I will keep some pull requests open if I'm not sure whether those libraries are awesome, you could [vote for them](https://github.com/vinta/awesome-python/pulls) by adding :+1: to them. Pull requests will be merged when their votes reach **20**. - -- - - +--- -If you have any question about this opinionated list, do not hesitate to contact me [@vinta](https://twitter.com/vinta) on Twitter or open an issue on GitHub. +If you have any question about this opinionated list, do not hesitate to contact [@VintaChen](https://twitter.com/VintaChen) on Twitter. diff --git a/SPONSORSHIP.md b/SPONSORSHIP.md new file mode 100644 index 000000000..3f9e8a68e --- /dev/null +++ b/SPONSORSHIP.md @@ -0,0 +1,36 @@ +# Sponsor awesome-python + +**The #10 most-starred repository on all of GitHub.** + +awesome-python is where Python developers go to discover tools. When someone searches Google for "best Python libraries," they land here. When ChatGPT recommends Python tools, it references this list. When developers evaluate frameworks, this is the list they check. + +Your sponsorship puts your product in front of developers at the exact moment they're choosing what to use. + +## By the Numbers + +| Metric | Value | +| ------------ | ---------------------------------------------------------------------------------------------------- | +| Stars | ![Stars](https://img.shields.io/github/stars/vinta/awesome-python?style=for-the-badge) | +| Forks | ![Forks](https://img.shields.io/github/forks/vinta/awesome-python?style=for-the-badge) | +| Watchers | ![Watchers](https://img.shields.io/github/watchers/vinta/awesome-python?style=for-the-badge) | +| Contributors | ![Contributors](https://img.shields.io/github/contributors/vinta/awesome-python?style=for-the-badge) | + +Top referrers: GitHub, Google Search, YouTube, Reddit, ChatGPT — developers actively searching for and evaluating Python tools. + +## Sponsorship Tiers + +### Logo Sponsor — $500/month (2 slots) + +Your logo and a one-line description at the top of the README, seen by every visitor. + +### Link Sponsor — $150/month (5 slots) + +A text link with your product name at the top of the README, right below logo sponsors. + +## Past Sponsors + +- [Warp](https://www.warp.dev/) - https://github.com/vinta/awesome-python/pull/2766 + +## Get Started + +Email [vinta.chen@gmail.com](mailto:vinta.chen@gmail.com?subject=awesome-python%20Sponsorship) with your company name and preferred tier. Most sponsors are set up within 24 hours. diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index 0f6ced663..000000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -awesome-python.com \ No newline at end of file diff --git a/docs/css/extra.css b/docs/css/extra.css deleted file mode 100644 index 1230d796a..000000000 --- a/docs/css/extra.css +++ /dev/null @@ -1,9 +0,0 @@ -@media (min-width: 960px) { - html { - scroll-behavior: smooth; - } - - .md-content__inner > ul:nth-child(5) { - display: none; - } -} diff --git a/mkdocs.yml b/mkdocs.yml deleted file mode 100644 index 67a0373a4..000000000 --- a/mkdocs.yml +++ /dev/null @@ -1,26 +0,0 @@ -site_name: Awesome Python -site_url: https://awesome-python.com -site_description: A curated list of awesome Python frameworks, libraries and software -site_author: Vinta Chen -repo_name: vinta/awesome-python -repo_url: https://github.com/vinta/awesome-python -theme: - name: material - palette: - primary: red - accent: pink -extra: - social: - - type: github - link: https://github.com/vinta - - type: twitter - link: https://twitter.com/vinta - - type: linkedin - link: https://www.linkedin.com/in/vinta -google_analytics: - - UA-510626-7 - - auto -extra_css: - - css/extra.css -nav: - - "Life is short, you need Python.": "index.md" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..31fee98f1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,31 @@ +[project] +name = "awesome-python" +version = "0.1.0" +description = "An opinionated list of awesome Python frameworks, libraries, software and resources." +authors = [{ name = "Vinta Chen", email = "vinta.chen@gmail.com" }] +readme = "README.md" +license = "MIT" +requires-python = ">=3.13" +dependencies = [] + +[project.urls] +Homepage = "https://awesome-python.com/" +Repository = "https://github.com/vinta/awesome-python" + +[dependency-groups] +build = ["httpx==0.28.1", "jinja2==3.1.6", "markdown-it-py==4.0.0"] +lint = ["ruff==0.15.6"] +test = ["pytest==9.0.2"] +dev = [ + { include-group = "build" }, + { include-group = "lint" }, + { include-group = "test" }, + "watchdog==6.0.0", +] + +[tool.pytest.ini_options] +testpaths = ["website/tests"] +pythonpath = ["website"] + +[tool.ruff] +line-length = 200 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 89d64c303..000000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -mkdocs==1.0.4 -mkdocs-material==4.0.2 diff --git a/sort.py b/sort.py old mode 100644 new mode 100755 index d646c3faf..431bd02b4 --- a/sort.py +++ b/sort.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # coding: utf-8 """ @@ -29,10 +30,10 @@ def sort_blocks(): # Sorting the libraries inner_blocks = sorted(blocks[0].split('##')) - for i in range(1 , len(inner_blocks)): + for i in range(1, len(inner_blocks)): if inner_blocks[i][0] != '#': inner_blocks[i] = '##' + inner_blocks[i] - inner_blocks=''.join(inner_blocks) + inner_blocks = ''.join(inner_blocks) # Replacing the non-sorted libraries by the sorted ones and gathering all at the final_README file blocks[0] = inner_blocks @@ -68,7 +69,9 @@ def main(): with open('README.md', 'w+') as sorted_file: # Then all of the blocks are sorted individually - blocks = [''.join(sorted(block, key=lambda s: s.lower())) for block in blocks] + blocks = [ + ''.join(sorted(block, key=str.lower)) for block in blocks + ] # And the result is written back to README.md sorted_file.write(''.join(blocks)) diff --git a/uv.lock b/uv.lock new file mode 100644 index 000000000..ecff72915 --- /dev/null +++ b/uv.lock @@ -0,0 +1,307 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, +] + +[[package]] +name = "awesome-python" +version = "0.1.0" +source = { virtual = "." } + +[package.dev-dependencies] +build = [ + { name = "httpx" }, + { name = "jinja2" }, + { name = "markdown-it-py" }, +] +dev = [ + { name = "httpx" }, + { name = "jinja2" }, + { name = "markdown-it-py" }, + { name = "pytest" }, + { name = "ruff" }, + { name = "watchdog" }, +] +lint = [ + { name = "ruff" }, +] +test = [ + { name = "pytest" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +build = [ + { name = "httpx", specifier = "==0.28.1" }, + { name = "jinja2", specifier = "==3.1.6" }, + { name = "markdown-it-py", specifier = "==4.0.0" }, +] +dev = [ + { name = "httpx", specifier = "==0.28.1" }, + { name = "jinja2", specifier = "==3.1.6" }, + { name = "markdown-it-py", specifier = "==4.0.0" }, + { name = "pytest", specifier = "==9.0.2" }, + { name = "ruff", specifier = "==0.15.6" }, + { name = "watchdog", specifier = "==6.0.0" }, +] +lint = [{ name = "ruff", specifier = "==0.15.6" }] +test = [{ name = "pytest", specifier = "==9.0.2" }] + +[[package]] +name = "certifi" +version = "2026.2.25" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/df/f8629c19c5318601d3121e230f74cbee7a3732339c52b21daa2b82ef9c7d/ruff-0.15.6.tar.gz", hash = "sha256:8394c7bb153a4e3811a4ecdacd4a8e6a4fa8097028119160dffecdcdf9b56ae4", size = 4597916, upload-time = "2026-03-12T23:05:47.51Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/2f/4e03a7e5ce99b517e98d3b4951f411de2b0fa8348d39cf446671adcce9a2/ruff-0.15.6-py3-none-linux_armv6l.whl", hash = "sha256:7c98c3b16407b2cf3d0f2b80c80187384bc92c6774d85fefa913ecd941256fff", size = 10508953, upload-time = "2026-03-12T23:05:17.246Z" }, + { url = "https://files.pythonhosted.org/packages/70/60/55bcdc3e9f80bcf39edf0cd272da6fa511a3d94d5a0dd9e0adf76ceebdb4/ruff-0.15.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ee7dcfaad8b282a284df4aa6ddc2741b3f4a18b0555d626805555a820ea181c3", size = 10942257, upload-time = "2026-03-12T23:05:23.076Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/005c29bd1726c0f492bfa215e95154cf480574140cb5f867c797c18c790b/ruff-0.15.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3bd9967851a25f038fc8b9ae88a7fbd1b609f30349231dffaa37b6804923c4bb", size = 10322683, upload-time = "2026-03-12T23:05:33.738Z" }, + { url = "https://files.pythonhosted.org/packages/5f/74/2f861f5fd7cbb2146bddb5501450300ce41562da36d21868c69b7a828169/ruff-0.15.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13f4594b04e42cd24a41da653886b04d2ff87adbf57497ed4f728b0e8a4866f8", size = 10660986, upload-time = "2026-03-12T23:05:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a1/309f2364a424eccb763cdafc49df843c282609f47fe53aa83f38272389e0/ruff-0.15.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2ed8aea2f3fe57886d3f00ea5b8aae5bf68d5e195f487f037a955ff9fbaac9e", size = 10332177, upload-time = "2026-03-12T23:05:56.145Z" }, + { url = "https://files.pythonhosted.org/packages/30/41/7ebf1d32658b4bab20f8ac80972fb19cd4e2c6b78552be263a680edc55ac/ruff-0.15.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70789d3e7830b848b548aae96766431c0dc01a6c78c13381f423bf7076c66d15", size = 11170783, upload-time = "2026-03-12T23:06:01.742Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/6d488f6adca047df82cd62c304638bcb00821c36bd4881cfca221561fdfc/ruff-0.15.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:542aaf1de3154cea088ced5a819ce872611256ffe2498e750bbae5247a8114e9", size = 12044201, upload-time = "2026-03-12T23:05:28.697Z" }, + { url = "https://files.pythonhosted.org/packages/71/68/e6f125df4af7e6d0b498f8d373274794bc5156b324e8ab4bf5c1b4fc0ec7/ruff-0.15.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c22e6f02c16cfac3888aa636e9eba857254d15bbacc9906c9689fdecb1953ab", size = 11421561, upload-time = "2026-03-12T23:05:31.236Z" }, + { url = "https://files.pythonhosted.org/packages/f1/9f/f85ef5fd01a52e0b472b26dc1b4bd228b8f6f0435975442ffa4741278703/ruff-0.15.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98893c4c0aadc8e448cfa315bd0cc343a5323d740fe5f28ef8a3f9e21b381f7e", size = 11310928, upload-time = "2026-03-12T23:05:45.288Z" }, + { url = "https://files.pythonhosted.org/packages/8c/26/b75f8c421f5654304b89471ed384ae8c7f42b4dff58fa6ce1626d7f2b59a/ruff-0.15.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:70d263770d234912374493e8cc1e7385c5d49376e41dfa51c5c3453169dc581c", size = 11235186, upload-time = "2026-03-12T23:05:50.677Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d4/d5a6d065962ff7a68a86c9b4f5500f7d101a0792078de636526c0edd40da/ruff-0.15.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:55a1ad63c5a6e54b1f21b7514dfadc0c7fb40093fa22e95143cf3f64ebdcd512", size = 10635231, upload-time = "2026-03-12T23:05:37.044Z" }, + { url = "https://files.pythonhosted.org/packages/d6/56/7c3acf3d50910375349016cf33de24be021532042afbed87942858992491/ruff-0.15.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8dc473ba093c5ec238bb1e7429ee676dca24643c471e11fbaa8a857925b061c0", size = 10340357, upload-time = "2026-03-12T23:06:04.748Z" }, + { url = "https://files.pythonhosted.org/packages/06/54/6faa39e9c1033ff6a3b6e76b5df536931cd30caf64988e112bbf91ef5ce5/ruff-0.15.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:85b042377c2a5561131767974617006f99f7e13c63c111b998f29fc1e58a4cfb", size = 10860583, upload-time = "2026-03-12T23:05:58.978Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/509a201b843b4dfb0b32acdedf68d951d3377988cae43949ba4c4133a96a/ruff-0.15.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cef49e30bc5a86a6a92098a7fbf6e467a234d90b63305d6f3ec01225a9d092e0", size = 11410976, upload-time = "2026-03-12T23:05:39.955Z" }, + { url = "https://files.pythonhosted.org/packages/6c/25/3fc9114abf979a41673ce877c08016f8e660ad6cf508c3957f537d2e9fa9/ruff-0.15.6-py3-none-win32.whl", hash = "sha256:bbf67d39832404812a2d23020dda68fee7f18ce15654e96fb1d3ad21a5fe436c", size = 10616872, upload-time = "2026-03-12T23:05:42.451Z" }, + { url = "https://files.pythonhosted.org/packages/89/7a/09ece68445ceac348df06e08bf75db72d0e8427765b96c9c0ffabc1be1d9/ruff-0.15.6-py3-none-win_amd64.whl", hash = "sha256:aee25bc84c2f1007ecb5037dff75cef00414fdf17c23f07dc13e577883dca406", size = 11787271, upload-time = "2026-03-12T23:05:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d0/578c47dd68152ddddddf31cd7fc67dc30b7cdf639a86275fda821b0d9d98/ruff-0.15.6-py3-none-win_arm64.whl", hash = "sha256:c34de3dd0b0ba203be50ae70f5910b17188556630e2178fd7d79fc030eb0d837", size = 11060497, upload-time = "2026-03-12T23:05:25.968Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] diff --git a/website/build.py b/website/build.py new file mode 100644 index 000000000..b19d65b76 --- /dev/null +++ b/website/build.py @@ -0,0 +1,340 @@ +#!/usr/bin/env python3 +"""Build a single-page HTML site from README.md for the awesome-python website.""" + +import json +import re +import shutil +from pathlib import Path +from typing import TypedDict + +from jinja2 import Environment, FileSystemLoader +from readme_parser import parse_readme, slugify + +# Thematic grouping of categories. Each category name must match exactly +# as it appears in README.md (the ## heading text). +SECTION_GROUPS: list[tuple[str, list[str]]] = [ + ( + "Web & API", + [ + "Admin Panels", + "CMS", + "Email", + "Static Site Generator", + "URL Manipulation", + "Web Frameworks", + "RESTful API", + "GraphQL", + "WebSocket", + "ASGI Servers", + "WSGI Servers", + "HTTP Clients", + "Template Engine", + "Web Asset Management", + "Web Content Extracting", + "Web Crawling", + ], + ), + ( + "AI & ML", + [ + "AI and Agents", + "Machine Learning", + "Deep Learning", + "Computer Vision", + "Natural Language Processing", + "Recommender Systems", + "Robotics", + ], + ), + ( + "Data & Science", + [ + "Data Analysis", + "Data Validation", + "Data Visualization", + "Geolocation", + "Science", + "Quantum Computing", + ], + ), + ( + "DevOps & Infrastructure", + [ + "DevOps Tools", + "Distributed Computing", + "Task Queues", + "Job Scheduler", + "Serverless Frameworks", + "Logging", + "Processes", + "Shell", + "Network Virtualization", + "RPC Servers", + ], + ), + ( + "Database & Storage", + [ + "Database", + "Database Drivers", + "ORM", + "Caching", + "Search", + "Serialization", + ], + ), + ( + "Development Tools", + [ + "Testing", + "Debugging Tools", + "Code Analysis", + "Build Tools", + "Algorithms and Design Patterns", + "Refactoring", + "Documentation", + "Editor Plugins and IDEs", + "Interactive Interpreter", + ], + ), + ( + "CLI & GUI", + [ + "Command-line Interface Development", + "Command-line Tools", + "GUI Development", + ], + ), + ( + "Content & Media", + [ + "Audio", + "Video", + "Game Development", + "Image Processing", + "Internationalization", + "HTML Manipulation", + "Text Processing", + "Specific Formats Processing", + "File Manipulation", + "Downloader", + ], + ), + ( + "System & Runtime", + [ + "Asynchronous Programming", + "Environment Management", + "Package Management", + "Package Repositories", + "Date and Time", + "Distribution", + "Hardware", + "Implementations", + "Microsoft Windows", + "Built-in Classes Enhancement", + "Functional Programming", + "Configuration Files", + ], + ), + ( + "Security & Auth", + [ + "Authentication", + "Cryptography", + "Penetration Testing", + "Permissions", + ], + ), + ("Resources", []), # Filled dynamically from parsed resources +] + + +def group_categories( + categories: list[dict], + resources: list[dict], +) -> list[dict]: + """Organize categories and resources into thematic section groups.""" + cat_by_name = {c["name"]: c for c in categories} + groups = [] + grouped_names: set[str] = set() + + for group_name, cat_names in SECTION_GROUPS: + grouped_names.update(cat_names) + if group_name == "Resources": + group_cats = list(resources) + else: + group_cats = [cat_by_name[n] for n in cat_names if n in cat_by_name] + + if group_cats: + groups.append( + { + "name": group_name, + "slug": slugify(group_name), + "categories": group_cats, + } + ) + + # Any categories not in a group go into "Other" + ungrouped = [c for c in categories if c["name"] not in grouped_names] + if ungrouped: + groups.append( + { + "name": "Other", + "slug": "other", + "categories": ungrouped, + } + ) + + return groups + + +class Entry(TypedDict): + name: str + url: str + description: str + category: str + group: str + stars: int | None + owner: str | None + last_commit_at: str | None + + +class StarData(TypedDict): + stars: int + owner: str + last_commit_at: str + fetched_at: str + + +GITHUB_REPO_URL_RE = re.compile(r"^https?://github\.com/([^/]+/[^/]+?)(?:\.git)?/?$") + + +def extract_github_repo(url: str) -> str | None: + """Extract owner/repo from a GitHub repo URL. Returns None for non-GitHub URLs.""" + m = GITHUB_REPO_URL_RE.match(url) + return m.group(1) if m else None + + +def load_stars(path: Path) -> dict[str, StarData]: + """Load star data from JSON. Returns empty dict if file doesn't exist or is corrupt.""" + if path.exists(): + try: + return json.loads(path.read_text(encoding="utf-8")) + except json.JSONDecodeError: + return {} + return {} + + +def sort_entries(entries: list[dict]) -> list[dict]: + """Sort entries by stars descending, then name ascending. No-star entries go last.""" + + def sort_key(entry: dict) -> tuple[int, int, str]: + stars = entry["stars"] + name = entry["name"].lower() + if stars is None: + return (1, 0, name) + return (0, -stars, name) + + return sorted(entries, key=sort_key) + + +def extract_entries( + categories: list[dict], + groups: list[dict], +) -> list[dict]: + """Flatten categories into individual library entries for table display.""" + cat_to_group: dict[str, str] = {} + for group in groups: + for cat in group["categories"]: + cat_to_group[cat["name"]] = group["name"] + + entries: list[dict] = [] + for cat in categories: + group_name = cat_to_group.get(cat["name"], "Other") + for entry in cat["entries"]: + entries.append( + { + "name": entry["name"], + "url": entry["url"], + "description": entry["description"], + "category": cat["name"], + "group": group_name, + "stars": None, + "owner": None, + "last_commit_at": None, + "also_see": entry["also_see"], + } + ) + return entries + + +def build(repo_root: str) -> None: + """Main build: parse README, render single-page HTML via Jinja2 templates.""" + repo = Path(repo_root) + website = repo / "website" + readme_text = (repo / "README.md").read_text(encoding="utf-8") + + subtitle = "" + for line in readme_text.split("\n"): + stripped = line.strip() + if stripped and not stripped.startswith("#"): + subtitle = stripped + break + + categories, resources = parse_readme(readme_text) + # All fields pre-computed: entry_count, content_html, preview, description + + total_entries = sum(c["entry_count"] for c in categories) + groups = group_categories(categories, resources) + entries = extract_entries(categories, groups) + + stars_data = load_stars(website / "data" / "github_stars.json") + for entry in entries: + repo_key = extract_github_repo(entry["url"]) + if repo_key and repo_key in stars_data: + sd = stars_data[repo_key] + entry["stars"] = sd["stars"] + entry["owner"] = sd["owner"] + entry["last_commit_at"] = sd.get("last_commit_at", "") + + entries = sort_entries(entries) + + env = Environment( + loader=FileSystemLoader(website / "templates"), + autoescape=True, + ) + + site_dir = website / "output" + if site_dir.exists(): + shutil.rmtree(site_dir) + site_dir.mkdir(parents=True) + + tpl_index = env.get_template("index.html") + (site_dir / "index.html").write_text( + tpl_index.render( + categories=categories, + resources=resources, + groups=groups, + subtitle=subtitle, + entries=entries, + total_entries=total_entries, + total_categories=len(categories), + ), + encoding="utf-8", + ) + + static_src = website / "static" + static_dst = site_dir / "static" + if static_src.exists(): + shutil.copytree(static_src, static_dst, dirs_exist_ok=True) + + shutil.copy(repo / "README.md", site_dir / "llms.txt") + + print(f"Built single page with {len(categories)} categories + {len(resources)} resources") + print(f"Total entries: {total_entries}") + print(f"Output: {site_dir}") + + +if __name__ == "__main__": + build(str(Path(__file__).parent.parent)) diff --git a/website/fetch_github_stars.py b/website/fetch_github_stars.py new file mode 100644 index 000000000..c63985314 --- /dev/null +++ b/website/fetch_github_stars.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +"""Fetch GitHub star counts and owner info for all GitHub repos in README.md.""" + +import json +import os +import re +import sys +from datetime import datetime, timezone +from pathlib import Path + +import httpx + +from build import extract_github_repo, load_stars + +CACHE_MAX_AGE_HOURS = 12 +DATA_DIR = Path(__file__).parent / "data" +CACHE_FILE = DATA_DIR / "github_stars.json" +README_PATH = Path(__file__).parent.parent / "README.md" +GRAPHQL_URL = "https://api.github.com/graphql" +BATCH_SIZE = 50 + + +def extract_github_repos(text: str) -> set[str]: + """Extract unique owner/repo pairs from GitHub URLs in markdown text.""" + repos = set() + for url in re.findall(r"https?://github\.com/[^\s)\]]+", text): + repo = extract_github_repo(url.split("#")[0].rstrip("/")) + if repo: + repos.add(repo) + return repos + + +def save_cache(cache: dict) -> None: + """Write the star cache to disk, creating data/ dir if needed.""" + DATA_DIR.mkdir(parents=True, exist_ok=True) + CACHE_FILE.write_text( + json.dumps(cache, indent=2, ensure_ascii=False) + "\n", + encoding="utf-8", + ) + + +def build_graphql_query(repos: list[str]) -> str: + """Build a GraphQL query with aliases for up to 100 repos.""" + if not repos: + return "" + parts = [] + for i, repo in enumerate(repos): + owner, name = repo.split("/", 1) + if '"' in owner or '"' in name: + continue + parts.append( + f'repo_{i}: repository(owner: "{owner}", name: "{name}") ' + f"{{ stargazerCount owner {{ login }} defaultBranchRef {{ target {{ ... on Commit {{ committedDate }} }} }} }}" + ) + if not parts: + return "" + return "query { " + " ".join(parts) + " }" + + +def parse_graphql_response( + data: dict, + repos: list[str], +) -> dict[str, dict]: + """Parse GraphQL response into {owner/repo: {stars, owner}} dict.""" + result = {} + for i, repo in enumerate(repos): + node = data.get(f"repo_{i}") + if node is None: + continue + default_branch = node.get("defaultBranchRef") or {} + target = default_branch.get("target") or {} + result[repo] = { + "stars": node.get("stargazerCount", 0), + "owner": node.get("owner", {}).get("login", ""), + "last_commit_at": target.get("committedDate", ""), + } + return result + + +def fetch_batch( + repos: list[str], *, client: httpx.Client, +) -> dict[str, dict]: + """Fetch star data for a batch of repos via GitHub GraphQL API.""" + query = build_graphql_query(repos) + if not query: + return {} + resp = client.post(GRAPHQL_URL, json={"query": query}) + resp.raise_for_status() + result = resp.json() + if "errors" in result: + for err in result["errors"]: + print(f" Warning: {err.get('message', err)}", file=sys.stderr) + data = result.get("data", {}) + return parse_graphql_response(data, repos) + + +def main() -> None: + """Fetch GitHub stars for all repos in README.md, updating the JSON cache.""" + token = os.environ.get("GITHUB_TOKEN", "") + if not token: + print("Error: GITHUB_TOKEN environment variable is required.", file=sys.stderr) + sys.exit(1) + + readme_text = README_PATH.read_text(encoding="utf-8") + current_repos = extract_github_repos(readme_text) + print(f"Found {len(current_repos)} GitHub repos in README.md") + + cache = load_stars(CACHE_FILE) + now = datetime.now(timezone.utc) + + # Prune entries not in current README + pruned = {k: v for k, v in cache.items() if k in current_repos} + if len(pruned) < len(cache): + print(f"Pruned {len(cache) - len(pruned)} stale cache entries") + cache = pruned + + # Determine which repos need fetching (missing or stale) + to_fetch = [] + for repo in sorted(current_repos): + entry = cache.get(repo) + if entry and "fetched_at" in entry: + fetched = datetime.fromisoformat(entry["fetched_at"]) + age_hours = (now - fetched).total_seconds() / 3600 + if age_hours < CACHE_MAX_AGE_HOURS: + continue + to_fetch.append(repo) + + print(f"{len(to_fetch)} repos to fetch ({len(current_repos) - len(to_fetch)} cached)") + + if not to_fetch: + save_cache(cache) + print("Cache is up to date.") + return + + # Fetch in batches + fetched_count = 0 + skipped_repos: list[str] = [] + + with httpx.Client( + headers={"Authorization": f"bearer {token}", "Content-Type": "application/json"}, + transport=httpx.HTTPTransport(retries=2), + timeout=30, + ) as client: + for i in range(0, len(to_fetch), BATCH_SIZE): + batch = to_fetch[i : i + BATCH_SIZE] + batch_num = i // BATCH_SIZE + 1 + total_batches = (len(to_fetch) + BATCH_SIZE - 1) // BATCH_SIZE + print(f"Fetching batch {batch_num}/{total_batches} ({len(batch)} repos)...") + + try: + results = fetch_batch(batch, client=client) + except httpx.HTTPStatusError as e: + print(f"HTTP error {e.response.status_code}", file=sys.stderr) + if e.response.status_code == 401: + print("Error: Invalid GITHUB_TOKEN.", file=sys.stderr) + sys.exit(1) + print("Saving partial cache and exiting.", file=sys.stderr) + save_cache(cache) + sys.exit(1) + + now_iso = now.isoformat() + for repo in batch: + if repo in results: + cache[repo] = { + "stars": results[repo]["stars"], + "owner": results[repo]["owner"], + "last_commit_at": results[repo]["last_commit_at"], + "fetched_at": now_iso, + } + fetched_count += 1 + else: + skipped_repos.append(repo) + + # Save after each batch in case of interruption + save_cache(cache) + + if skipped_repos: + print(f"Skipped {len(skipped_repos)} repos (deleted/private/renamed)") + print(f"Done. Fetched {fetched_count} repos, {len(cache)} total cached.") + + +if __name__ == "__main__": + main() diff --git a/website/readme_parser.py b/website/readme_parser.py new file mode 100644 index 000000000..97fd37af7 --- /dev/null +++ b/website/readme_parser.py @@ -0,0 +1,388 @@ +"""Parse README.md into structured section data using markdown-it-py AST.""" + +from __future__ import annotations + +import re +from typing import TypedDict + +from markdown_it import MarkdownIt +from markdown_it.tree import SyntaxTreeNode +from markupsafe import escape + + +class AlsoSee(TypedDict): + name: str + url: str + + +class ParsedEntry(TypedDict): + name: str + url: str + description: str # inline HTML, properly escaped + also_see: list[AlsoSee] + + +class ParsedSection(TypedDict): + name: str + slug: str + description: str # plain text, links resolved to text + entries: list[ParsedEntry] + entry_count: int + preview: str + content_html: str # rendered HTML, properly escaped + + +# --- Slugify ---------------------------------------------------------------- + +_SLUG_NON_ALNUM_RE = re.compile(r"[^a-z0-9\s-]") +_SLUG_WHITESPACE_RE = re.compile(r"[\s]+") +_SLUG_MULTI_DASH_RE = re.compile(r"-+") + + +def slugify(name: str) -> str: + """Convert a category name to a URL-friendly slug.""" + slug = name.lower() + slug = _SLUG_NON_ALNUM_RE.sub("", slug) + slug = _SLUG_WHITESPACE_RE.sub("-", slug.strip()) + slug = _SLUG_MULTI_DASH_RE.sub("-", slug) + return slug + + +# --- Inline renderers ------------------------------------------------------- + + +def render_inline_html(children: list[SyntaxTreeNode]) -> str: + """Render inline AST nodes to HTML with proper escaping.""" + parts: list[str] = [] + for child in children: + match child.type: + case "text": + parts.append(str(escape(child.content))) + case "softbreak": + parts.append(" ") + case "link": + href = str(escape(child.attrGet("href") or "")) + inner = render_inline_html(child.children) + parts.append( + f'{inner}' + ) + case "em": + parts.append(f"{render_inline_html(child.children)}") + case "strong": + parts.append(f"{render_inline_html(child.children)}") + case "code_inline": + parts.append(f"{escape(child.content)}") + case "html_inline": + parts.append(str(escape(child.content))) + return "".join(parts) + + +def render_inline_text(children: list[SyntaxTreeNode]) -> str: + """Render inline AST nodes to plain text (links become their text).""" + parts: list[str] = [] + for child in children: + match child.type: + case "text": + parts.append(child.content) + case "softbreak": + parts.append(" ") + case "code_inline": + parts.append(child.content) + case "em" | "strong" | "link": + parts.append(render_inline_text(child.children)) + return "".join(parts) + + +# --- AST helpers ------------------------------------------------------------- + + +def _heading_text(node: SyntaxTreeNode) -> str: + """Extract plain text from a heading node.""" + for child in node.children: + if child.type == "inline": + return render_inline_text(child.children) + return "" + + +def _extract_description(nodes: list[SyntaxTreeNode]) -> str: + """Extract description from the first paragraph if it's a single block. + + Pattern: _Libraries for foo._ -> "Libraries for foo." + """ + if not nodes: + return "" + first = nodes[0] + if first.type != "paragraph": + return "" + for child in first.children: + if child.type == "inline" and len(child.children) == 1: + em = child.children[0] + if em.type == "em": + return render_inline_text(em.children) + return "" + + +# --- Entry extraction -------------------------------------------------------- + +_DESC_SEP_RE = re.compile(r"^\s*[-\u2013\u2014]\s*") + + +def _find_child(node: SyntaxTreeNode, child_type: str) -> SyntaxTreeNode | None: + """Find first direct child of a given type.""" + for child in node.children: + if child.type == child_type: + return child + return None + + +def _find_inline(node: SyntaxTreeNode) -> SyntaxTreeNode | None: + """Find the inline node in a list_item's paragraph.""" + para = _find_child(node, "paragraph") + if para is None: + return None + return _find_child(para, "inline") + + +def _find_first_link(inline: SyntaxTreeNode) -> SyntaxTreeNode | None: + """Find the first link node among inline children.""" + for child in inline.children: + if child.type == "link": + return child + return None + + +def _is_leading_link(inline: SyntaxTreeNode, link: SyntaxTreeNode) -> bool: + """Check if the link is the first child of inline (a real entry, not a subcategory label).""" + return bool(inline.children) and inline.children[0] is link + + +def _extract_description_html(inline: SyntaxTreeNode, first_link: SyntaxTreeNode) -> str: + """Extract description HTML from inline content after the first link. + + AST: [link("name"), text(" - Description.")] -> "Description." + The separator (- / en-dash / em-dash) is stripped. + """ + link_idx = next((i for i, c in enumerate(inline.children) if c is first_link), None) + if link_idx is None: + return "" + desc_children = inline.children[link_idx + 1 :] + if not desc_children: + return "" + html = render_inline_html(desc_children) + return _DESC_SEP_RE.sub("", html) + + +def _parse_list_entries(bullet_list: SyntaxTreeNode) -> list[ParsedEntry]: + """Extract entries from a bullet_list AST node. + + Handles three patterns: + - Text-only list_item -> subcategory label -> recurse into nested list + - Link list_item with nested link-only items -> entry with also_see + - Link list_item without nesting -> simple entry + """ + entries: list[ParsedEntry] = [] + + for list_item in bullet_list.children: + if list_item.type != "list_item": + continue + + inline = _find_inline(list_item) + if inline is None: + continue + + first_link = _find_first_link(inline) + + if first_link is None or not _is_leading_link(inline, first_link): + # Subcategory label (plain text or text-before-link) — recurse into nested list + nested = _find_child(list_item, "bullet_list") + if nested: + entries.extend(_parse_list_entries(nested)) + continue + + # Entry with a link + name = render_inline_text(first_link.children) + url = first_link.attrGet("href") or "" + desc_html = _extract_description_html(inline, first_link) + + # Collect also_see from nested bullet_list + also_see: list[AlsoSee] = [] + nested = _find_child(list_item, "bullet_list") + if nested: + for sub_item in nested.children: + if sub_item.type != "list_item": + continue + sub_inline = _find_inline(sub_item) + if sub_inline: + sub_link = _find_first_link(sub_inline) + if sub_link: + also_see.append(AlsoSee( + name=render_inline_text(sub_link.children), + url=sub_link.attrGet("href") or "", + )) + + entries.append(ParsedEntry( + name=name, + url=url, + description=desc_html, + also_see=also_see, + )) + + return entries + + +def _parse_section_entries(content_nodes: list[SyntaxTreeNode]) -> list[ParsedEntry]: + """Extract all entries from a section's content nodes.""" + entries: list[ParsedEntry] = [] + for node in content_nodes: + if node.type == "bullet_list": + entries.extend(_parse_list_entries(node)) + return entries + + +# --- Content HTML rendering -------------------------------------------------- + + +def _render_bullet_list_html( + bullet_list: SyntaxTreeNode, + *, + is_sub: bool = False, +) -> str: + """Render a bullet_list node to HTML with entry/entry-sub/subcat classes.""" + out: list[str] = [] + + for list_item in bullet_list.children: + if list_item.type != "list_item": + continue + + inline = _find_inline(list_item) + if inline is None: + continue + + first_link = _find_first_link(inline) + + if first_link is None or not _is_leading_link(inline, first_link): + # Subcategory label (plain text or text-before-link) + label = str(escape(render_inline_text(inline.children))) + out.append(f'
{label}
') + nested = _find_child(list_item, "bullet_list") + if nested: + out.append(_render_bullet_list_html(nested, is_sub=False)) + continue + + # Entry with a link + name = str(escape(render_inline_text(first_link.children))) + url = str(escape(first_link.attrGet("href") or "")) + + if is_sub: + out.append(f'
{name}
') + else: + desc = _extract_description_html(inline, first_link) + if desc: + out.append( + f'
{name}' + f'{desc}
' + ) + else: + out.append(f'
{name}
') + + # Nested items under an entry with a link are sub-entries + nested = _find_child(list_item, "bullet_list") + if nested: + out.append(_render_bullet_list_html(nested, is_sub=True)) + + return "\n".join(out) + + +def _render_section_html(content_nodes: list[SyntaxTreeNode]) -> str: + """Render a section's content nodes to HTML.""" + parts: list[str] = [] + for node in content_nodes: + if node.type == "bullet_list": + parts.append(_render_bullet_list_html(node)) + return "\n".join(parts) + + +# --- Section splitting ------------------------------------------------------- + + +def _group_by_h2( + nodes: list[SyntaxTreeNode], +) -> list[ParsedSection]: + """Group AST nodes into sections by h2 headings.""" + sections: list[ParsedSection] = [] + current_name: str | None = None + current_body: list[SyntaxTreeNode] = [] + + def flush() -> None: + nonlocal current_name + if current_name is None: + return + desc = _extract_description(current_body) + content_nodes = current_body[1:] if desc else current_body + entries = _parse_section_entries(content_nodes) + entry_count = len(entries) + sum(len(e["also_see"]) for e in entries) + preview = ", ".join(e["name"] for e in entries[:4]) + content_html = _render_section_html(content_nodes) + + sections.append(ParsedSection( + name=current_name, + slug=slugify(current_name), + description=desc, + entries=entries, + entry_count=entry_count, + preview=preview, + content_html=content_html, + )) + current_name = None + + for node in nodes: + if node.type == "heading" and node.tag == "h2": + flush() + current_name = _heading_text(node) + current_body = [] + elif current_name is not None: + current_body.append(node) + + flush() + return sections + + +def parse_readme(text: str) -> tuple[list[ParsedSection], list[ParsedSection]]: + """Parse README.md text into categories and resources. + + Returns (categories, resources) where each is a list of ParsedSection dicts. + """ + md = MarkdownIt("commonmark") + tokens = md.parse(text) + root = SyntaxTreeNode(tokens) + children = root.children + + # Find thematic break (---), # Resources, and # Contributing in one pass + hr_idx = None + resources_idx = None + contributing_idx = None + for i, node in enumerate(children): + if hr_idx is None and node.type == "hr": + hr_idx = i + elif node.type == "heading" and node.tag == "h1": + text_content = _heading_text(node) + if text_content == "Resources": + resources_idx = i + elif text_content == "Contributing": + contributing_idx = i + if hr_idx is None: + return [], [] + + # Slice into category and resource ranges + cat_end = resources_idx or contributing_idx or len(children) + cat_nodes = children[hr_idx + 1 : cat_end] + + res_nodes: list[SyntaxTreeNode] = [] + if resources_idx is not None: + res_end = contributing_idx or len(children) + res_nodes = children[resources_idx + 1 : res_end] + + categories = _group_by_h2(cat_nodes) + resources = _group_by_h2(res_nodes) + + return categories, resources diff --git a/website/static/favicon.svg b/website/static/favicon.svg new file mode 100644 index 000000000..660a7c6f3 --- /dev/null +++ b/website/static/favicon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/website/static/main.js b/website/static/main.js new file mode 100644 index 000000000..ed04a5578 --- /dev/null +++ b/website/static/main.js @@ -0,0 +1,292 @@ +// State +var activeFilter = null; // { type: "cat"|"group", value: "..." } +var activeSort = { col: 'stars', order: 'desc' }; +var searchInput = document.querySelector('.search'); +var filterBar = document.querySelector('.filter-bar'); +var filterValue = document.querySelector('.filter-value'); +var filterClear = document.querySelector('.filter-clear'); +var noResults = document.querySelector('.no-results'); +var rows = document.querySelectorAll('.table tbody tr.row'); +var tags = document.querySelectorAll('.tag'); +var tbody = document.querySelector('.table tbody'); + +// Relative time formatting +function relativeTime(isoStr) { + var date = new Date(isoStr); + var now = new Date(); + var diffMs = now - date; + var diffHours = Math.floor(diffMs / 3600000); + var diffDays = Math.floor(diffMs / 86400000); + if (diffHours < 1) return 'just now'; + if (diffHours < 24) return diffHours === 1 ? '1 hour ago' : diffHours + ' hours ago'; + if (diffDays === 1) return 'yesterday'; + if (diffDays < 30) return diffDays + ' days ago'; + var diffMonths = Math.floor(diffDays / 30); + if (diffMonths < 12) return diffMonths === 1 ? '1 month ago' : diffMonths + ' months ago'; + var diffYears = Math.floor(diffDays / 365); + return diffYears === 1 ? '1 year ago' : diffYears + ' years ago'; +} + +// Format all commit date cells +document.querySelectorAll('.col-commit[data-commit]').forEach(function (td) { + var time = td.querySelector('time'); + if (time) time.textContent = relativeTime(td.dataset.commit); +}); + +// Store original row order for sort reset +rows.forEach(function (row, i) { + row._origIndex = i; + row._expandRow = row.nextElementSibling; +}); + +function collapseAll() { + var openRows = document.querySelectorAll('.table tbody tr.row.open'); + openRows.forEach(function (row) { + row.classList.remove('open'); + row.setAttribute('aria-expanded', 'false'); + }); +} + +function applyFilters() { + var query = searchInput ? searchInput.value.toLowerCase().trim() : ''; + var visibleCount = 0; + + // Collapse all expanded rows on filter/search change + collapseAll(); + + rows.forEach(function (row) { + var show = true; + + // Category/group filter + if (activeFilter) { + show = row.dataset[activeFilter.type] === activeFilter.value; + } + + // Text search + if (show && query) { + if (!row._searchText) { + var text = row.textContent.toLowerCase(); + var next = row.nextElementSibling; + if (next && next.classList.contains('expand-row')) { + text += ' ' + next.textContent.toLowerCase(); + } + row._searchText = text; + } + show = row._searchText.includes(query); + } + + if (row.hidden !== !show) row.hidden = !show; + + if (show) { + visibleCount++; + var numCell = row.cells[0]; + if (numCell.textContent !== String(visibleCount)) { + numCell.textContent = String(visibleCount); + } + } + }); + + if (noResults) noResults.hidden = visibleCount > 0; + + // Update tag highlights + tags.forEach(function (tag) { + var isActive = activeFilter + && tag.dataset.type === activeFilter.type + && tag.dataset.value === activeFilter.value; + tag.classList.toggle('active', isActive); + }); + + // Filter bar + if (filterBar) { + if (activeFilter) { + filterBar.hidden = false; + if (filterValue) filterValue.textContent = activeFilter.value; + } else { + filterBar.hidden = true; + } + } + + updateURL(); +} + +function updateURL() { + var params = new URLSearchParams(); + var query = searchInput ? searchInput.value.trim() : ''; + if (query) params.set('q', query); + if (activeFilter) { + params.set(activeFilter.type === 'cat' ? 'category' : 'group', activeFilter.value); + } + if (activeSort.col !== 'stars' || activeSort.order !== 'desc') { + params.set('sort', activeSort.col); + params.set('order', activeSort.order); + } + var qs = params.toString(); + history.replaceState(null, '', qs ? '?' + qs : location.pathname); +} + +function getSortValue(row, col) { + if (col === 'name') { + return row.querySelector('.col-name a').textContent.trim().toLowerCase(); + } + if (col === 'stars') { + var text = row.querySelector('.col-stars').textContent.trim().replace(/,/g, ''); + var num = parseInt(text, 10); + return isNaN(num) ? -1 : num; + } + if (col === 'commit-time') { + var attr = row.querySelector('.col-commit').getAttribute('data-commit'); + return attr ? new Date(attr).getTime() : 0; + } + return 0; +} + +function sortRows() { + var arr = Array.prototype.slice.call(rows); + if (activeSort) { + arr.sort(function (a, b) { + var aVal = getSortValue(a, activeSort.col); + var bVal = getSortValue(b, activeSort.col); + if (activeSort.col === 'name') { + var cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0; + if (cmp === 0) return a._origIndex - b._origIndex; + return activeSort.order === 'desc' ? -cmp : cmp; + } + if (aVal <= 0 && bVal <= 0) return a._origIndex - b._origIndex; + if (aVal <= 0) return 1; + if (bVal <= 0) return -1; + var cmp = aVal - bVal; + if (cmp === 0) return a._origIndex - b._origIndex; + return activeSort.order === 'desc' ? -cmp : cmp; + }); + } else { + arr.sort(function (a, b) { return a._origIndex - b._origIndex; }); + } + arr.forEach(function (row) { + tbody.appendChild(row); + tbody.appendChild(row._expandRow); + }); + applyFilters(); +} + +function updateSortIndicators() { + document.querySelectorAll('th[data-sort]').forEach(function (th) { + th.classList.remove('sort-asc', 'sort-desc'); + if (activeSort && th.dataset.sort === activeSort.col) { + th.classList.add('sort-' + activeSort.order); + } + }); +} + +// Expand/collapse: event delegation on tbody +if (tbody) { + tbody.addEventListener('click', function (e) { + // Don't toggle if clicking a link or tag button + if (e.target.closest('a') || e.target.closest('.tag')) return; + + var row = e.target.closest('tr.row'); + if (!row) return; + + var isOpen = row.classList.contains('open'); + if (isOpen) { + row.classList.remove('open'); + row.setAttribute('aria-expanded', 'false'); + } else { + row.classList.add('open'); + row.setAttribute('aria-expanded', 'true'); + } + }); + + // Keyboard: Enter or Space on focused .row toggles expand + tbody.addEventListener('keydown', function (e) { + if (e.key !== 'Enter' && e.key !== ' ') return; + var row = e.target.closest('tr.row'); + if (!row) return; + e.preventDefault(); + row.click(); + }); +} + +// Tag click: filter by category or group +tags.forEach(function (tag) { + tag.addEventListener('click', function (e) { + e.preventDefault(); + var type = tag.dataset.type; + var value = tag.dataset.value; + + // Toggle: click same filter again to clear + if (activeFilter && activeFilter.type === type && activeFilter.value === value) { + activeFilter = null; + } else { + activeFilter = { type: type, value: value }; + } + applyFilters(); + }); +}); + +// Clear filter +if (filterClear) { + filterClear.addEventListener('click', function () { + activeFilter = null; + applyFilters(); + }); +} + +// Column sorting +document.querySelectorAll('th[data-sort]').forEach(function (th) { + th.addEventListener('click', function () { + var col = th.dataset.sort; + var defaultOrder = col === 'name' ? 'asc' : 'desc'; + var altOrder = defaultOrder === 'asc' ? 'desc' : 'asc'; + if (activeSort && activeSort.col === col) { + if (activeSort.order === defaultOrder) activeSort = { col: col, order: altOrder }; + else activeSort = { col: 'stars', order: 'desc' }; + } else { + activeSort = { col: col, order: defaultOrder }; + } + sortRows(); + updateSortIndicators(); + }); +}); + +// Search input +if (searchInput) { + var searchTimer; + searchInput.addEventListener('input', function () { + clearTimeout(searchTimer); + searchTimer = setTimeout(applyFilters, 150); + }); + + // Keyboard shortcuts + document.addEventListener('keydown', function (e) { + if (e.key === '/' && !['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName) && !e.ctrlKey && !e.metaKey) { + e.preventDefault(); + searchInput.focus(); + } + if (e.key === 'Escape' && document.activeElement === searchInput) { + searchInput.value = ''; + activeFilter = null; + applyFilters(); + searchInput.blur(); + } + }); +} + +// Restore state from URL +(function () { + var params = new URLSearchParams(location.search); + var q = params.get('q'); + var cat = params.get('category'); + var group = params.get('group'); + var sort = params.get('sort'); + var order = params.get('order'); + if (q && searchInput) searchInput.value = q; + if (cat) activeFilter = { type: 'cat', value: cat }; + else if (group) activeFilter = { type: 'group', value: group }; + if ((sort === 'name' || sort === 'stars' || sort === 'commit-time') && (order === 'desc' || order === 'asc')) { + activeSort = { col: sort, order: order }; + } + if (q || cat || group || sort) { + sortRows(); + } + updateSortIndicators(); +})(); diff --git a/website/static/style.css b/website/static/style.css new file mode 100644 index 000000000..8f86f881d --- /dev/null +++ b/website/static/style.css @@ -0,0 +1,606 @@ +/* === Reset & Base === */ +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +:root { + --font-display: Georgia, "Noto Serif", "Times New Roman", serif; + --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; + + --text-xs: 0.9375rem; + --text-sm: 1rem; + --text-base: 1.125rem; + + --bg: oklch(99.5% 0.003 240); + --bg-hover: oklch(97% 0.008 240); + --text: oklch(15% 0.005 240); + --text-secondary: oklch(35% 0.005 240); + --text-muted: oklch(50% 0.005 240); + --border: oklch(90% 0.005 240); + --border-strong: oklch(75% 0.008 240); + --border-heavy: oklch(25% 0.01 240); + --bg-input: oklch(94.5% 0.035 240); + --accent: oklch(42% 0.14 240); + --accent-hover: oklch(32% 0.16 240); + --accent-light: oklch(97% 0.015 240); + --highlight: oklch(93% 0.10 90); + --highlight-text: oklch(35% 0.10 90); + --tag-text: oklch(45% 0.06 240); + --tag-hover-bg: oklch(93% 0.025 240); +} + +html { font-size: 16px; } + +body { + font-family: var(--font-body); + background: var(--bg); + color: var(--text); + line-height: 1.55; + min-height: 100vh; + display: flex; + flex-direction: column; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { color: var(--accent); text-decoration: none; text-underline-offset: 0.15em; } +a:hover { color: var(--accent-hover); text-decoration: underline; } + +/* === Skip Link === */ +.skip-link { + position: absolute; + left: -9999px; + top: 0; + padding: 0.5rem 1rem; + background: var(--text); + color: var(--bg); + font-size: var(--text-xs); + font-weight: 700; + z-index: 200; +} + +.skip-link:focus { left: 0; } + +/* === Hero === */ +.hero { + max-width: 1400px; + margin: 0 auto; + padding: 3.5rem 2rem 1.5rem; +} + +.hero-main { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: flex-start; + gap: 1rem; +} + +.hero-submit { + flex-shrink: 0; + padding: 0.4rem 1rem; + border: 1px solid var(--border-strong); + border-radius: 4px; + font-size: var(--text-sm); + color: var(--text); + text-decoration: none; + white-space: nowrap; + transition: border-color 0.2s, background 0.2s, color 0.2s; +} + +.hero-submit:hover { + border-color: var(--accent); + background: var(--accent-light); + color: var(--accent); + text-decoration: none; +} + +.hero-submit:active { + transform: scale(0.97); +} + +.hero-submit:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.hero h1 { + font-family: var(--font-display); + font-size: clamp(2rem, 5vw, 3rem); + font-weight: 400; + letter-spacing: -0.01em; + line-height: 1.1; + text-wrap: balance; + color: var(--accent); + margin-bottom: 0.75rem; +} + +.hero-sub { + font-size: var(--text-base); + color: var(--text-secondary); + line-height: 1.6; + margin-bottom: 0.5rem; + text-wrap: pretty; +} + +.hero-sub a { color: var(--text-secondary); font-weight: 600; } +.hero-sub a:hover { color: var(--accent); } + +.hero-gh { + font-size: var(--text-sm); + color: var(--text-muted); + font-weight: 500; +} + +.hero-gh:hover { color: var(--accent); } + +/* === Controls === */ +.controls { + max-width: 1400px; + margin: 0 auto; + padding: 0 2rem 1rem; +} + +.search-wrap { + position: relative; + margin-bottom: 0.75rem; +} + +.search-icon { + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + color: var(--text-muted); + pointer-events: none; +} + +.search { + width: 100%; + padding: 0.65rem 1rem 0.65rem 2.75rem; + border: 1px solid transparent; + border-radius: 4px; + background: var(--bg-input); + font-family: var(--font-body); + font-size: var(--text-sm); + color: var(--text); + transition: border-color 0.15s, background 0.15s; +} + +.search::placeholder { color: var(--text-muted); } + +.search:focus { + outline: 2px solid var(--accent); + outline-offset: 2px; + border-color: var(--accent); + background: var(--bg); +} + +.filter-bar[hidden] { display: none; } + +.filter-bar { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.5rem 0; + font-size: var(--text-sm); + color: var(--text-secondary); +} + +.filter-bar strong { + color: var(--text); +} + +.filter-clear { + background: none; + border: 1px solid var(--border); + border-radius: 4px; + padding: 0.35rem 0.65rem; + font-family: inherit; + font-size: var(--text-xs); + color: var(--text-muted); + cursor: pointer; + transition: border-color 0.15s, color 0.15s; +} + +.filter-clear:active { + transform: scale(0.97); +} + +.filter-clear:hover { + border-color: var(--text-muted); + color: var(--text); +} + +.filter-clear:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* === Table === */ +.table-wrap { + width: 100%; + padding: 0; + overflow-x: auto; +} + +.table-wrap:focus { + outline: 2px solid var(--accent); + outline-offset: -2px; +} + +.table { + width: 100%; + border-collapse: separate; + border-spacing: 0; + font-size: var(--text-sm); +} + +.table thead th { + text-align: left; + font-weight: 700; + font-size: var(--text-base); + color: var(--text); + padding: 0.65rem 0.75rem; + border-bottom: 2px solid var(--border-heavy); + position: sticky; + top: 0; + background: var(--bg); + z-index: 10; + white-space: nowrap; +} + +.table thead th:first-child, +.table tbody td:first-child { + padding-left: max(2rem, calc(50vw - 700px + 2rem)); +} + +.table thead th:last-child, +.table tbody td:last-child { + padding-right: max(2rem, calc(50vw - 700px + 2rem)); +} + +.table tbody td { + padding: 0.7rem 0.75rem; + border-bottom: 1px solid var(--border); + vertical-align: top; + transition: background 0.15s; +} + +.table tbody tr.row:not(.open):hover td { + background: var(--bg-hover); +} + +.table tbody tr[hidden] { display: none; } + +.col-num { + width: 3rem; + color: var(--text-muted); + font-variant-numeric: tabular-nums; + text-align: left; +} + +.col-name { + width: 30%; + overflow-wrap: anywhere; +} + +.col-name > a { + font-weight: 500; + color: var(--accent); + text-decoration: none; +} + +.col-name > a:hover { text-decoration: underline; color: var(--accent-hover); } + +/* === Sortable Headers === */ +th[data-sort] { + cursor: pointer; + user-select: none; +} + +th[data-sort]:hover { + color: var(--accent); +} + +th[data-sort]::after { + content: " ▼"; + opacity: 0; + transition: opacity 0.15s; +} + +th[data-sort="name"]::after { + content: " ▲"; +} + +th[data-sort]:hover::after { + opacity: 1; +} + +th[data-sort].sort-desc::after { + content: " ▼"; + opacity: 1; +} + +th[data-sort].sort-asc::after { + content: " ▲"; + opacity: 1; +} + +/* === Stars Column === */ +.col-stars { + width: 5rem; + font-variant-numeric: tabular-nums; + white-space: nowrap; + color: var(--text-secondary); + text-align: right; +} + +/* === Arrow Column === */ +.col-arrow { + width: 2.5rem; + text-align: center; +} + +.arrow { + display: inline-block; + font-size: 0.8rem; + color: var(--accent); + transition: transform 0.15s ease; +} + +.row.open .arrow { + transform: rotate(90deg); +} + +/* === Row Click === */ +.row { cursor: pointer; } +.row:active td { background: var(--bg-hover); } + +.row:focus-visible td { + outline: none; + background: var(--bg-hover); + box-shadow: inset 2px 0 0 var(--accent); +} + +/* === Expand Row === */ +.expand-row { + display: none; +} + +.row.open + .expand-row { + display: table-row; +} + +.row.open td { + background: var(--accent-light); + border-bottom-color: transparent; + padding-bottom: 0.1rem; +} + +.expand-row td { + padding: 0.15rem 0.75rem 0.75rem; + background: var(--accent-light); + border-bottom: 1px solid var(--border); +} + +@keyframes expand-in { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.expand-content { + font-size: var(--text-sm); + color: var(--text-secondary); + line-height: 1.6; + text-wrap: pretty; + animation: expand-in 0.2s cubic-bezier(0.25, 1, 0.5, 1); +} + +.expand-tags { + display: flex; + gap: 0.4rem; + margin-bottom: 0.4rem; +} + +.expand-tag { + font-size: var(--text-xs); + color: var(--tag-text); + background: var(--bg); + padding: 0.15rem 0.4rem; + border-radius: 3px; +} + +.expand-also-see { + margin-top: 0.25rem; + font-size: var(--text-xs); + color: var(--text-muted); +} + +.expand-also-see a { + color: var(--accent); + text-decoration: none; +} + +.expand-also-see a:hover { + text-decoration: underline; +} + +.expand-meta { + margin-top: 0.25rem; + font-size: var(--text-xs); + color: var(--text-muted); + font-weight: normal; +} + +.expand-meta a { + color: var(--accent); + text-decoration: none; +} + +.expand-meta a:hover { + text-decoration: underline; +} + +.expand-sep { + margin: 0 0.25rem; + color: var(--border); +} + +.col-cat { + white-space: nowrap; +} + +.col-cat .tag + .tag { + margin-left: 0.35rem; +} + +/* === Last Commit Column === */ +.col-commit { + width: 9rem; + white-space: nowrap; + color: var(--text-muted); +} + +/* === Tags === */ +.tag { + position: relative; + background: var(--accent-light); + border: none; + font-family: inherit; + font-size: var(--text-xs); + color: var(--tag-text); + cursor: pointer; + padding: 0.25rem 0.5rem; + border-radius: 3px; + white-space: nowrap; + transition: background 0.15s, color 0.15s; +} + +/* Expand touch target to 44x44px minimum */ +.tag::after { + content: ""; + position: absolute; + inset: -0.5rem -0.25rem; +} + +.tag:active { + transform: scale(0.95); +} + +.tag:hover { + background: var(--tag-hover-bg); + color: var(--accent); +} + +.tag:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +.tag.active { + background: var(--highlight); + color: var(--highlight-text); + font-weight: 600; +} + +/* === Noscript === */ +.noscript-msg { + text-align: center; + padding: 1rem; + color: var(--text-muted); +} + +/* === No Results === */ +.no-results { + max-width: 1400px; + margin: 0 auto; + padding: 3rem 2rem; + font-size: var(--text-base); + color: var(--text-muted); + text-align: center; +} + +/* === Footer === */ +.footer { + margin-top: auto; + border-top: none; + width: 100%; + padding: 1.25rem 2rem; + font-size: var(--text-xs); + color: var(--text-muted); + background: var(--bg-input); + display: flex; + align-items: center; + justify-content: flex-end; + gap: 0.5rem; +} + +.footer a { color: var(--accent); text-decoration: none; } +.footer a:hover { color: var(--accent-hover); text-decoration: underline; } + +.footer-sep { color: var(--border-strong); } + +/* === Responsive === */ +@media (max-width: 900px) { + .col-commit { display: none; } + .tag-group { display: none; } + .col-name { width: 50%; } +} + +@media (max-width: 640px) { + .hero { padding: 2rem 1.25rem 1rem; } + .controls { padding: 0 1.25rem 0.75rem; } + + .table { table-layout: auto; } + + .table thead th, + .table tbody td { + padding-left: 0.5rem; + padding-right: 0.5rem; + } + + .table thead th:first-child, + .table tbody td:first-child { padding-left: 0.25rem; } + + .table thead th:last-child, + .table tbody td:last-child { padding-right: 0.25rem; } + + .table thead th { font-size: var(--text-sm); } + + .col-num { width: 2rem; } + .col-stars { width: 4.75rem; } + .col-arrow { width: 1.25rem; } + .col-cat { display: none; } + .col-name { + width: auto; + white-space: normal; + } + .footer { padding: 1.25rem; justify-content: center; flex-wrap: wrap; } +} + +/* === Screen Reader Only === */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* === Reduced Motion === */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/website/templates/base.html b/website/templates/base.html new file mode 100644 index 000000000..ea7c7e521 --- /dev/null +++ b/website/templates/base.html @@ -0,0 +1,64 @@ + + + + + + {% block title %}Awesome Python{% endblock %} + + + + + + + + + + + + + + + +
{% block content %}{% endblock %}
+ + + + + + + diff --git a/website/templates/index.html b/website/templates/index.html new file mode 100644 index 000000000..8569016ae --- /dev/null +++ b/website/templates/index.html @@ -0,0 +1,167 @@ +{% extends "base.html" %} {% block content %} +
+
+
+

Awesome Python

+

+ {{ subtitle }}
Maintained by + @vinta + and + @JinyangWang27. +

+ awesome-python on GitHub → +
+ Submit a Project +
+
+ +

Search and filter

+
+
+ + + + + +
+ +
+ +

Results

+
+ + + + + + + + + + + + + {% for entry in entries %} + + + + + + + + + + + + + + {% endfor %} + +
#Project NameGitHub StarsLast CommitCategoryDetails
+
+ {% if entry.description %} +
{{ entry.description | safe }}
+ {% endif %} {% if entry.also_see %} +
+ Also see: {% for see in entry.also_see %}{{ see.name }}{% if not loop.last %}, {% endif %}{% endfor %} +
+ {% endif %} + +
+
+
+ + +{% endblock %} diff --git a/website/tests/test_build.py b/website/tests/test_build.py new file mode 100644 index 000000000..a75c22949 --- /dev/null +++ b/website/tests/test_build.py @@ -0,0 +1,354 @@ +"""Tests for the build module.""" + +import json +import shutil +import textwrap +from pathlib import Path + +from build import ( + build, + extract_github_repo, + group_categories, + load_stars, + sort_entries, +) +from readme_parser import slugify + +# --------------------------------------------------------------------------- +# slugify +# --------------------------------------------------------------------------- + + +class TestSlugify: + def test_simple(self): + assert slugify("Admin Panels") == "admin-panels" + + def test_uppercase_acronym(self): + assert slugify("RESTful API") == "restful-api" + + def test_all_caps(self): + assert slugify("CMS") == "cms" + + def test_hyphenated_input(self): + assert slugify("Command-line Tools") == "command-line-tools" + + def test_special_chars(self): + assert slugify("Editor Plugins and IDEs") == "editor-plugins-and-ides" + + def test_single_word(self): + assert slugify("Audio") == "audio" + + def test_extra_spaces(self): + assert slugify(" Date and Time ") == "date-and-time" + + +# --------------------------------------------------------------------------- +# group_categories +# --------------------------------------------------------------------------- + + +class TestGroupCategories: + def test_groups_known_categories(self): + cats = [ + {"name": "Web Frameworks", "slug": "web-frameworks"}, + {"name": "Testing", "slug": "testing"}, + ] + groups = group_categories(cats, []) + group_names = [g["name"] for g in groups] + assert "Web & API" in group_names + assert "Development Tools" in group_names + + def test_ungrouped_go_to_other(self): + cats = [{"name": "Unknown Category", "slug": "unknown-category"}] + groups = group_categories(cats, []) + group_names = [g["name"] for g in groups] + assert "Other" in group_names + + def test_resources_grouped(self): + resources = [{"name": "Newsletters", "slug": "newsletters"}] + groups = group_categories([], resources) + group_names = [g["name"] for g in groups] + assert "Resources" in group_names + + +# --------------------------------------------------------------------------- +# build (integration) +# --------------------------------------------------------------------------- + + +class TestBuild: + def _make_repo(self, tmp_path, readme): + (tmp_path / "README.md").write_text(readme, encoding="utf-8") + tpl_dir = tmp_path / "website" / "templates" + tpl_dir.mkdir(parents=True) + (tpl_dir / "base.html").write_text( + "{% block title %}{% endblock %}" + "" + "{% block content %}{% endblock %}", + encoding="utf-8", + ) + (tpl_dir / "index.html").write_text( + '{% extends "base.html" %}{% block content %}' + "{% for group in groups %}" + '
' + "

{{ group.name }}

" + "{% for cat in group.categories %}" + '
' + "{{ cat.name }}" + "{{ cat.preview }}" + "{{ cat.entry_count }}" + '' + "
" + "{% endfor %}" + "
" + "{% endfor %}" + "{% endblock %}", + encoding="utf-8", + ) + + def test_build_creates_single_page(self, tmp_path): + readme = textwrap.dedent("""\ + # Awesome Python + + Intro. + + --- + + ## Widgets + + _Widget libraries._ + + - [w1](https://example.com) - A widget. + + ## Gadgets + + _Gadget tools._ + + - [g1](https://example.com) - A gadget. + + # Resources + + Info. + + ## Newsletters + + - [NL](https://example.com) + + # Contributing + + Help! + """) + self._make_repo(tmp_path, readme) + build(str(tmp_path)) + + site = tmp_path / "website" / "output" + assert (site / "index.html").exists() + # No category sub-pages + assert not (site / "categories").exists() + + def test_build_cleans_stale_output(self, tmp_path): + readme = textwrap.dedent("""\ + # T + + --- + + ## Only + + - [x](https://x.com) - X. + + # Contributing + + Done. + """) + self._make_repo(tmp_path, readme) + + stale = tmp_path / "website" / "output" / "categories" / "stale" + stale.mkdir(parents=True) + (stale / "index.html").write_text("old", encoding="utf-8") + + build(str(tmp_path)) + + assert not (tmp_path / "website" / "output" / "categories" / "stale").exists() + + def test_index_contains_category_names(self, tmp_path): + readme = textwrap.dedent("""\ + # T + + --- + + ## Alpha + + - [a](https://x.com) - A. + + ## Beta + + - [b](https://x.com) - B. + + # Contributing + + Done. + """) + self._make_repo(tmp_path, readme) + build(str(tmp_path)) + + index_html = (tmp_path / "website" / "output" / "index.html").read_text() + assert "Alpha" in index_html + assert "Beta" in index_html + + def test_index_contains_preview_text(self, tmp_path): + readme = textwrap.dedent("""\ + # T + + --- + + ## Stuff + + - [django](https://x.com) - A framework. + - [flask](https://x.com) - A micro. + + # Contributing + + Done. + """) + self._make_repo(tmp_path, readme) + build(str(tmp_path)) + + index_html = (tmp_path / "website" / "output" / "index.html").read_text() + assert "django" in index_html + assert "flask" in index_html + + def test_build_with_stars_sorts_by_stars(self, tmp_path): + readme = textwrap.dedent("""\ + # T + + --- + + ## Stuff + + - [low-stars](https://github.com/org/low) - Low. + - [high-stars](https://github.com/org/high) - High. + - [no-stars](https://example.com/none) - None. + + # Contributing + + Done. + """) + (tmp_path / "README.md").write_text(readme, encoding="utf-8") + + # Copy real templates + real_tpl = Path(__file__).parent / ".." / "templates" + tpl_dir = tmp_path / "website" / "templates" + shutil.copytree(real_tpl, tpl_dir) + + # Create mock star data + data_dir = tmp_path / "website" / "data" + data_dir.mkdir(parents=True) + stars = { + "org/high": {"stars": 5000, "owner": "org", "fetched_at": "2026-01-01T00:00:00+00:00"}, + "org/low": {"stars": 100, "owner": "org", "fetched_at": "2026-01-01T00:00:00+00:00"}, + } + (data_dir / "github_stars.json").write_text(json.dumps(stars), encoding="utf-8") + + build(str(tmp_path)) + + html = (tmp_path / "website" / "output" / "index.html").read_text(encoding="utf-8") + # Star-sorted: high-stars (5000) before low-stars (100) before no-stars (None) + assert html.index("high-stars") < html.index("low-stars") + assert html.index("low-stars") < html.index("no-stars") + # Formatted star counts + assert "5,000" in html + assert "100" in html + # Expand content present + assert "expand-content" in html + + +# --------------------------------------------------------------------------- +# extract_github_repo +# --------------------------------------------------------------------------- + + +class TestExtractGithubRepo: + def test_github_url(self): + assert extract_github_repo("https://github.com/psf/requests") == "psf/requests" + + def test_non_github_url(self): + assert extract_github_repo("https://foss.heptapod.net/pypy/pypy") is None + + def test_github_io_url(self): + assert extract_github_repo("https://user.github.io/proj") is None + + def test_trailing_slash(self): + assert extract_github_repo("https://github.com/org/repo/") == "org/repo" + + def test_deep_path(self): + assert extract_github_repo("https://github.com/org/repo/tree/main") is None + + def test_dot_git_suffix(self): + assert extract_github_repo("https://github.com/org/repo.git") == "org/repo" + + def test_org_only(self): + assert extract_github_repo("https://github.com/org") is None + + +# --------------------------------------------------------------------------- +# load_stars +# --------------------------------------------------------------------------- + + +class TestLoadStars: + def test_returns_empty_when_missing(self, tmp_path): + result = load_stars(tmp_path / "nonexistent.json") + assert result == {} + + def test_loads_valid_json(self, tmp_path): + data = {"psf/requests": {"stars": 52467, "owner": "psf", "fetched_at": "2026-01-01T00:00:00+00:00"}} + f = tmp_path / "stars.json" + f.write_text(json.dumps(data), encoding="utf-8") + result = load_stars(f) + assert result["psf/requests"]["stars"] == 52467 + + def test_returns_empty_on_corrupt_json(self, tmp_path): + f = tmp_path / "stars.json" + f.write_text("not json", encoding="utf-8") + result = load_stars(f) + assert result == {} + + +# --------------------------------------------------------------------------- +# sort_entries +# --------------------------------------------------------------------------- + + +class TestSortEntries: + def test_sorts_by_stars_descending(self): + entries = [ + {"name": "a", "stars": 100, "url": ""}, + {"name": "b", "stars": 500, "url": ""}, + {"name": "c", "stars": 200, "url": ""}, + ] + result = sort_entries(entries) + assert [e["name"] for e in result] == ["b", "c", "a"] + + def test_equal_stars_sorted_alphabetically(self): + entries = [ + {"name": "beta", "stars": 100, "url": ""}, + {"name": "alpha", "stars": 100, "url": ""}, + ] + result = sort_entries(entries) + assert [e["name"] for e in result] == ["alpha", "beta"] + + def test_no_stars_go_to_bottom(self): + entries = [ + {"name": "no-stars", "stars": None, "url": ""}, + {"name": "has-stars", "stars": 50, "url": ""}, + ] + result = sort_entries(entries) + assert [e["name"] for e in result] == ["has-stars", "no-stars"] + + def test_no_stars_sorted_alphabetically(self): + entries = [ + {"name": "zebra", "stars": None, "url": ""}, + {"name": "apple", "stars": None, "url": ""}, + ] + result = sort_entries(entries) + assert [e["name"] for e in result] == ["apple", "zebra"] diff --git a/website/tests/test_fetch_github_stars.py b/website/tests/test_fetch_github_stars.py new file mode 100644 index 000000000..6c9eb383d --- /dev/null +++ b/website/tests/test_fetch_github_stars.py @@ -0,0 +1,231 @@ +"""Tests for fetch_github_stars module.""" + +import json +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) +from fetch_github_stars import ( + build_graphql_query, + extract_github_repos, + parse_graphql_response, + save_cache, +) + + +class TestExtractGithubRepos: + def test_extracts_owner_repo_from_github_url(self): + readme = "* [requests](https://github.com/psf/requests) - HTTP lib." + result = extract_github_repos(readme) + assert result == {"psf/requests"} + + def test_multiple_repos(self): + readme = ( + "* [requests](https://github.com/psf/requests) - HTTP.\n" + "* [flask](https://github.com/pallets/flask) - Micro." + ) + result = extract_github_repos(readme) + assert result == {"psf/requests", "pallets/flask"} + + def test_ignores_non_github_urls(self): + readme = "* [pypy](https://foss.heptapod.net/pypy/pypy) - Fast Python." + result = extract_github_repos(readme) + assert result == set() + + def test_ignores_github_io_urls(self): + readme = "* [docs](https://user.github.io/project) - Docs site." + result = extract_github_repos(readme) + assert result == set() + + def test_ignores_github_wiki_and_blob_urls(self): + readme = ( + "* [wiki](https://github.com/org/repo/wiki) - Wiki.\n" + "* [file](https://github.com/org/repo/blob/main/f.py) - File." + ) + result = extract_github_repos(readme) + assert result == set() + + def test_handles_trailing_slash(self): + readme = "* [lib](https://github.com/org/repo/) - Lib." + result = extract_github_repos(readme) + assert result == {"org/repo"} + + def test_deduplicates(self): + readme = ( + "* [a](https://github.com/org/repo) - A.\n" + "* [b](https://github.com/org/repo) - B." + ) + result = extract_github_repos(readme) + assert result == {"org/repo"} + + def test_strips_fragment(self): + readme = "* [lib](https://github.com/org/repo#section) - Lib." + result = extract_github_repos(readme) + assert result == {"org/repo"} + + +class TestSaveCache: + def test_creates_directory_and_writes_json(self, tmp_path, monkeypatch): + data_dir = tmp_path / "data" + cache_file = data_dir / "stars.json" + monkeypatch.setattr("fetch_github_stars.DATA_DIR", data_dir) + monkeypatch.setattr("fetch_github_stars.CACHE_FILE", cache_file) + save_cache({"a/b": {"stars": 1}}) + assert cache_file.exists() + assert json.loads(cache_file.read_text(encoding="utf-8")) == {"a/b": {"stars": 1}} + + +class TestBuildGraphqlQuery: + def test_single_repo(self): + query = build_graphql_query(["psf/requests"]) + assert "repository" in query + assert 'owner: "psf"' in query + assert 'name: "requests"' in query + assert "stargazerCount" in query + + def test_multiple_repos_use_aliases(self): + query = build_graphql_query(["psf/requests", "pallets/flask"]) + assert "repo_0:" in query + assert "repo_1:" in query + + def test_empty_list(self): + query = build_graphql_query([]) + assert query == "" + + def test_skips_repos_with_quotes_in_name(self): + query = build_graphql_query(['org/"bad"']) + assert query == "" + + def test_skips_only_bad_repos(self): + query = build_graphql_query(["good/repo", 'bad/"repo"']) + assert "good" in query + assert "bad" not in query + + +class TestParseGraphqlResponse: + def test_parses_star_count_and_owner(self): + data = { + "repo_0": { + "stargazerCount": 52467, + "owner": {"login": "psf"}, + } + } + repos = ["psf/requests"] + result = parse_graphql_response(data, repos) + assert result["psf/requests"]["stars"] == 52467 + assert result["psf/requests"]["owner"] == "psf" + + def test_skips_null_repos(self): + data = {"repo_0": None} + repos = ["deleted/repo"] + result = parse_graphql_response(data, repos) + assert result == {} + + def test_handles_missing_owner(self): + data = {"repo_0": {"stargazerCount": 100}} + repos = ["org/repo"] + result = parse_graphql_response(data, repos) + assert result["org/repo"]["owner"] == "" + + def test_multiple_repos(self): + data = { + "repo_0": {"stargazerCount": 100, "owner": {"login": "a"}}, + "repo_1": {"stargazerCount": 200, "owner": {"login": "b"}}, + } + repos = ["a/x", "b/y"] + result = parse_graphql_response(data, repos) + assert len(result) == 2 + assert result["a/x"]["stars"] == 100 + assert result["b/y"]["stars"] == 200 + + +class TestMainSkipsFreshCache: + """Verify that main() skips fetching when all cache entries are fresh.""" + + def test_skips_fetch_when_cache_is_fresh(self, tmp_path, monkeypatch, capsys): + from datetime import datetime, timedelta, timezone + + from fetch_github_stars import main + + # Set up a minimal README with one repo + readme = tmp_path / "README.md" + readme.write_text("* [req](https://github.com/psf/requests) - HTTP.\n") + monkeypatch.setattr("fetch_github_stars.README_PATH", readme) + + # Pre-populate cache with a fresh entry (1 hour ago) + data_dir = tmp_path / "data" + data_dir.mkdir() + cache_file = data_dir / "github_stars.json" + now = datetime.now(timezone.utc) + fresh_cache = { + "psf/requests": { + "stars": 52000, + "owner": "psf", + "last_commit_at": "2025-01-01T00:00:00+00:00", + "fetched_at": (now - timedelta(hours=1)).isoformat(), + } + } + cache_file.write_text(json.dumps(fresh_cache), encoding="utf-8") + monkeypatch.setattr("fetch_github_stars.CACHE_FILE", cache_file) + monkeypatch.setattr("fetch_github_stars.DATA_DIR", data_dir) + monkeypatch.setenv("GITHUB_TOKEN", "fake-token") + + main() + + output = capsys.readouterr().out + assert "0 repos to fetch" in output + assert "Cache is up to date" in output + + def test_fetches_when_cache_is_stale(self, tmp_path, monkeypatch, capsys): + from datetime import datetime, timedelta, timezone + from unittest.mock import MagicMock + + from fetch_github_stars import main + + # Set up a minimal README with one repo + readme = tmp_path / "README.md" + readme.write_text("* [req](https://github.com/psf/requests) - HTTP.\n") + monkeypatch.setattr("fetch_github_stars.README_PATH", readme) + + # Pre-populate cache with a stale entry (24 hours ago) + data_dir = tmp_path / "data" + data_dir.mkdir() + cache_file = data_dir / "github_stars.json" + now = datetime.now(timezone.utc) + stale_cache = { + "psf/requests": { + "stars": 52000, + "owner": "psf", + "last_commit_at": "2025-01-01T00:00:00+00:00", + "fetched_at": (now - timedelta(hours=24)).isoformat(), + } + } + cache_file.write_text(json.dumps(stale_cache), encoding="utf-8") + monkeypatch.setattr("fetch_github_stars.CACHE_FILE", cache_file) + monkeypatch.setattr("fetch_github_stars.DATA_DIR", data_dir) + monkeypatch.setenv("GITHUB_TOKEN", "fake-token") + + # Mock httpx.Client to avoid real API calls + mock_response = MagicMock() + mock_response.json.return_value = { + "data": { + "repo_0": { + "stargazerCount": 53000, + "owner": {"login": "psf"}, + "defaultBranchRef": {"target": {"committedDate": "2025-06-01T00:00:00Z"}}, + } + } + } + mock_response.raise_for_status = MagicMock() + mock_client = MagicMock() + mock_client.__enter__ = MagicMock(return_value=mock_client) + mock_client.__exit__ = MagicMock(return_value=False) + mock_client.post.return_value = mock_response + monkeypatch.setattr("fetch_github_stars.httpx.Client", lambda **kwargs: mock_client) + + main() + + output = capsys.readouterr().out + assert "1 repos to fetch" in output + assert "Done. Fetched 1 repos" in output + mock_client.post.assert_called_once() diff --git a/website/tests/test_readme_parser.py b/website/tests/test_readme_parser.py new file mode 100644 index 000000000..1e51036af --- /dev/null +++ b/website/tests/test_readme_parser.py @@ -0,0 +1,424 @@ +"""Tests for the readme_parser module.""" + +import os +import textwrap + +import pytest + +from readme_parser import ( + _parse_section_entries, + _render_section_html, + parse_readme, + render_inline_html, + render_inline_text, +) + +from markdown_it import MarkdownIt +from markdown_it.tree import SyntaxTreeNode + + +def _parse_inline(md_text: str) -> list[SyntaxTreeNode]: + """Helper: parse a single paragraph and return its inline children.""" + md = MarkdownIt("commonmark") + root = SyntaxTreeNode(md.parse(md_text)) + # root > paragraph > inline > children + return root.children[0].children[0].children + + +class TestRenderInlineHtml: + def test_plain_text_escapes_html(self): + children = _parse_inline("Hello & friends") + assert render_inline_html(children) == "Hello <world> & friends" + + def test_link_with_target(self): + children = _parse_inline("[name](https://example.com)") + html = render_inline_html(children) + assert 'href="https://example.com"' in html + assert 'target="_blank"' in html + assert 'rel="noopener"' in html + assert ">name" in html + + def test_emphasis(self): + children = _parse_inline("*italic* text") + assert "italic" in render_inline_html(children) + + def test_strong(self): + children = _parse_inline("**bold** text") + assert "bold" in render_inline_html(children) + + def test_code_inline(self): + children = _parse_inline("`some code`") + assert "some code" in render_inline_html(children) + + def test_mixed_link_and_text(self): + children = _parse_inline("See [foo](https://x.com) for details.") + html = render_inline_html(children) + assert "See " in html + assert ">foo" in html + assert " for details." in html + + +class TestRenderInlineText: + def test_plain_text(self): + children = _parse_inline("Hello world") + assert render_inline_text(children) == "Hello world" + + def test_link_becomes_text(self): + children = _parse_inline("See [awesome-algos](https://github.com/x/y).") + assert render_inline_text(children) == "See awesome-algos." + + def test_emphasis_stripped(self): + children = _parse_inline("*italic* text") + assert render_inline_text(children) == "italic text" + + def test_code_inline_kept(self): + children = _parse_inline("`code` here") + assert render_inline_text(children) == "code here" + + +MINIMAL_README = textwrap.dedent("""\ + # Awesome Python + + Some intro text. + + --- + + ## Alpha + + _Libraries for alpha stuff._ + + - [lib-a](https://example.com/a) - Does A. + - [lib-b](https://example.com/b) - Does B. + + ## Beta + + _Tools for beta._ + + - [lib-c](https://example.com/c) - Does C. + + # Resources + + Where to discover resources. + + ## Newsletters + + - [News One](https://example.com/n1) + - [News Two](https://example.com/n2) + + ## Podcasts + + - [Pod One](https://example.com/p1) + + # Contributing + + Please contribute! +""") + + +class TestParseReadmeSections: + def test_category_count(self): + cats, resources = parse_readme(MINIMAL_README) + assert len(cats) == 2 + + def test_resource_count(self): + cats, resources = parse_readme(MINIMAL_README) + assert len(resources) == 2 + + def test_category_names(self): + cats, _ = parse_readme(MINIMAL_README) + assert cats[0]["name"] == "Alpha" + assert cats[1]["name"] == "Beta" + + def test_category_slugs(self): + cats, _ = parse_readme(MINIMAL_README) + assert cats[0]["slug"] == "alpha" + assert cats[1]["slug"] == "beta" + + def test_category_description(self): + cats, _ = parse_readme(MINIMAL_README) + assert cats[0]["description"] == "Libraries for alpha stuff." + assert cats[1]["description"] == "Tools for beta." + + def test_resource_names(self): + _, resources = parse_readme(MINIMAL_README) + assert resources[0]["name"] == "Newsletters" + assert resources[1]["name"] == "Podcasts" + + def test_contributing_skipped(self): + cats, resources = parse_readme(MINIMAL_README) + all_names = [c["name"] for c in cats] + [r["name"] for r in resources] + assert "Contributing" not in all_names + + def test_no_separator(self): + cats, resources = parse_readme("# Just a heading\n\nSome text.\n") + assert cats == [] + assert resources == [] + + def test_no_description(self): + readme = textwrap.dedent("""\ + # Title + + --- + + ## NullDesc + + - [item](https://x.com) - Thing. + + # Resources + + ## Tips + + - [tip](https://x.com) + + # Contributing + + Done. + """) + cats, resources = parse_readme(readme) + assert cats[0]["description"] == "" + assert cats[0]["entries"][0]["name"] == "item" + + def test_description_with_link_stripped(self): + readme = textwrap.dedent("""\ + # T + + --- + + ## Algos + + _Algorithms. Also see [awesome-algos](https://example.com)._ + + - [lib](https://x.com) - Lib. + + # Contributing + + Done. + """) + cats, _ = parse_readme(readme) + assert cats[0]["description"] == "Algorithms. Also see awesome-algos." + + +def _content_nodes(md_text: str) -> list[SyntaxTreeNode]: + """Helper: parse markdown and return all block nodes.""" + md = MarkdownIt("commonmark") + root = SyntaxTreeNode(md.parse(md_text)) + return root.children + + +class TestParseSectionEntries: + def test_flat_entries(self): + nodes = _content_nodes( + "- [django](https://example.com/d) - A web framework.\n" + "- [flask](https://example.com/f) - A micro framework.\n" + ) + entries = _parse_section_entries(nodes) + assert len(entries) == 2 + assert entries[0]["name"] == "django" + assert entries[0]["url"] == "https://example.com/d" + assert "web framework" in entries[0]["description"] + assert entries[0]["also_see"] == [] + assert entries[1]["name"] == "flask" + + def test_link_only_entry(self): + nodes = _content_nodes("- [tool](https://x.com)\n") + entries = _parse_section_entries(nodes) + assert len(entries) == 1 + assert entries[0]["name"] == "tool" + assert entries[0]["description"] == "" + + def test_subcategorized_entries(self): + nodes = _content_nodes( + "- Algorithms\n" + " - [algos](https://x.com/a) - Algo lib.\n" + " - [sorts](https://x.com/s) - Sort lib.\n" + "- Design Patterns\n" + " - [patterns](https://x.com/p) - Pattern lib.\n" + ) + entries = _parse_section_entries(nodes) + assert len(entries) == 3 + assert entries[0]["name"] == "algos" + assert entries[2]["name"] == "patterns" + + def test_text_before_link_is_subcategory(self): + nodes = _content_nodes( + "- MySQL - [awesome-mysql](http://example.com/awesome-mysql/)\n" + " - [mysqlclient](https://example.com/mysqlclient) - MySQL connector.\n" + " - [pymysql](https://example.com/pymysql) - Pure Python MySQL driver.\n" + ) + entries = _parse_section_entries(nodes) + # awesome-mysql is a subcategory label, not an entry + assert len(entries) == 2 + names = [e["name"] for e in entries] + assert "awesome-mysql" not in names + assert "mysqlclient" in names + assert "pymysql" in names + + def test_also_see_sub_entries(self): + nodes = _content_nodes( + "- [asyncio](https://docs.python.org/3/library/asyncio.html) - Async I/O.\n" + " - [awesome-asyncio](https://github.com/timofurrer/awesome-asyncio)\n" + "- [trio](https://github.com/python-trio/trio) - Friendly async.\n" + ) + entries = _parse_section_entries(nodes) + assert len(entries) == 2 + assert entries[0]["name"] == "asyncio" + assert len(entries[0]["also_see"]) == 1 + assert entries[0]["also_see"][0]["name"] == "awesome-asyncio" + assert entries[1]["name"] == "trio" + assert entries[1]["also_see"] == [] + + def test_entry_count_includes_also_see(self): + readme = textwrap.dedent("""\ + # T + + --- + + ## Async + + - [asyncio](https://x.com) - Async I/O. + - [awesome-asyncio](https://y.com) + - [trio](https://z.com) - Friendly async. + + # Contributing + + Done. + """) + cats, _ = parse_readme(readme) + # 2 main entries + 1 also_see = 3 + assert cats[0]["entry_count"] == 3 + + def test_preview_first_four_names(self): + readme = textwrap.dedent("""\ + # T + + --- + + ## Libs + + - [alpha](https://x.com) - A. + - [beta](https://x.com) - B. + - [gamma](https://x.com) - C. + - [delta](https://x.com) - D. + - [epsilon](https://x.com) - E. + + # Contributing + + Done. + """) + cats, _ = parse_readme(readme) + assert cats[0]["preview"] == "alpha, beta, gamma, delta" + + def test_description_html_escapes_xss(self): + nodes = _content_nodes('- [lib](https://x.com) - A lib.\n') + entries = _parse_section_entries(nodes) + assert "\n") + html = _render_section_html(nodes) + assert "