Skip to content

Commit

Permalink
Support python 3.13
Browse files Browse the repository at this point in the history
  • Loading branch information
Zaczero committed Sep 15, 2024
1 parent 0d289b0 commit e99d6bb
Show file tree
Hide file tree
Showing 8 changed files with 445 additions and 412 deletions.
26 changes: 14 additions & 12 deletions .github/workflows/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ name: Deployment

on:
push:
branches: ["main"]
branches:
- main
tags:
- "*"
pull_request:
branches: ["main"]
branches:
- main

jobs:
test:
name: Run tests
strategy:
matrix:
os: [ubuntu-24.04, macos-14]
os: [ubuntu-latest, macos-14]

runs-on: ${{ matrix.os }}
steps:
Expand All @@ -23,29 +25,29 @@ jobs:
- name: Install Nix
uses: cachix/install-nix-action@v27
with:
nix_path: nixpkgs=channel:nixpkgs-23.11-darwin
nix_path: nixpkgs=channel:nixpkgs-24.05-darwin

- name: Extract nixpkgs hash
- name: Generate cache key
run: |
nixpkgs_hash=$(egrep -o 'archive/[0-9a-f]{40}\.tar\.gz' shell.nix | cut -d'/' -f2 | cut -d'.' -f1)
echo "NIXPKGS_HASH=$nixpkgs_hash" >> $GITHUB_ENV
echo "CACHE_KEY=${{ runner.os }}-$nixpkgs_hash" >> $GITHUB_ENV
- name: Cache Nix store
uses: actions/cache@v4
id: nix-cache
with:
key: nix-${{ runner.os }}-${{ env.NIXPKGS_HASH }}
key: nix-${{ env.CACHE_KEY }}
path: /tmp/nix-cache

- name: Import Nix store cache
if: steps.nix-cache.outputs.cache-hit == 'true'
run: |
nix-store --import < /tmp/nix-cache
- name: Cache Python packages
- name: Cache Python venv
uses: actions/cache@v4
with:
key: python-${{ runner.os }}-${{ hashFiles('poetry.lock') }}
key: python-${{ env.CACHE_KEY }}-${{ hashFiles('poetry.lock') }}
path: .venv

- name: Install dependencies
Expand All @@ -70,7 +72,7 @@ jobs:
- name: Run tests
run: |
nix-shell --pure --run run-tests
nix-shell --pure --run "run-tests term"
- name: Build distribution
run: |
Expand All @@ -86,7 +88,7 @@ jobs:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
name: Publish to PyPI
needs: test
runs-on: ubuntu-24.04
runs-on: ubuntu-latest

environment:
name: pypi
Expand All @@ -108,7 +110,7 @@ jobs:
publish-gh:
name: Publish to GitHub Release
needs: publish-pypi
runs-on: ubuntu-24.04
runs-on: ubuntu-latest

permissions:
id-token: write
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# starlette-compress

[![Support my work](https://shields.monicz.dev/badge/%E2%99%A5%EF%B8%8F%20Support%20my%20work-purple)](https://monicz.dev/#support-my-work)
[![Liberapay Patrons](https://shields.monicz.dev/liberapay/patrons/Zaczero?logo=liberapay)](https://liberapay.com/Zaczero/)
[![PyPI - Python Version](https://shields.monicz.dev/pypi/pyversions/starlette-compress)](https://pypi.org/project/starlette-compress)
[![Liberapay Patrons](https://shields.monicz.dev/liberapay/patrons/Zaczero?logo=liberapay&label=Patrons)](https://liberapay.com/Zaczero/)
[![GitHub Sponsors](https://shields.monicz.dev/github/sponsors/Zaczero?logo=github&label=Sponsors&color=%23db61a2)](https://github.com/sponsors/Zaczero)

**starlette-compress** is a fast and simple middleware for compressing responses in [Starlette](https://www.starlette.io). It supports more compression algorithms than Starlette's built-in GZipMiddleware, and has more sensible defaults.

Expand Down
615 changes: 327 additions & 288 deletions poetry.lock

Large diffs are not rendered by default.

150 changes: 75 additions & 75 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,46 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: The Unlicense (Unlicense)",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware",
"Typing :: Typed",
]
description = "Compression middleware for Starlette - supporting ZStd, Brotli, and GZip"
keywords = ["starlette", "middleware", "compression", "zstd", "brotli", "gzip", "http"]
keywords = [
"brotli",
"compression",
"fastapi",
"gzip",
"http",
"middleware",
"starlette",
"zstd",
]
license = "Unlicense"
name = "starlette-compress"
readme = "README.md"
repository = "https://github.com/Zaczero/starlette-compress"
version = "1.0.1"
version = "1.1.0"

[tool.poetry.dependencies]
brotli = {version = ">=1", markers = "platform_python_implementation == 'CPython'"}
brotlicffi = {version = ">=1", markers = "platform_python_implementation != 'CPython'"}
brotli = { version = ">=1", markers = "platform_python_implementation == 'CPython'" }
brotlicffi = { version = ">=1", markers = "platform_python_implementation != 'CPython'" }
python = "^3.8"
starlette = "*"
zstandard = ">=0.15"

[tool.poetry.group.test.dependencies]
brotlicffi = "^1.1.0.0"
httpx = "<1"
mypy = "^1.0.0"
pytest = "^8.0.0"
pytest-cov = "^5.0.0"
trio = "<1"
uvloop = "<1"
uvloop = { version = "<1", allow-prereleases = true }

[build-system]
build-backend = "poetry.core.masonry.api"
Expand Down Expand Up @@ -82,69 +92,69 @@ target-version = "py38"
# custom + https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
ignore = [
"ARG001", # unused-function-argument
"SIM108", # if-else-block-instead-of-if-exp
"W191", # tab-indentation
"E111", # indentation-with-invalid-multiple
"E114", # indentation-with-invalid-multiple-comment
"E117", # over-indented
"E501", # line-too-long
"D206", # indent-with-spaces
"D300", # triple-single-quotes
"Q000", # bad-quotes-inline-string
"Q001", # bad-quotes-multiline-string
"Q002", # bad-quotes-docstring
"Q003", # avoidable-escaped-quote
"COM812", # missing-trailing-comma
"COM819", # prohibited-trailing-comma
"D206", # indent-with-spaces
"D300", # triple-single-quotes
"E111", # indentation-with-invalid-multiple
"E114", # indentation-with-invalid-multiple-comment
"E117", # over-indented
"E501", # line-too-long
"ISC001", # single-line-implicit-string-concatenation
"ISC002", # multi-line-implicit-string-concatenation
"S101", # assert
"Q000", # bad-quotes-inline-string
"Q001", # bad-quotes-multiline-string
"Q002", # bad-quotes-docstring
"Q003", # avoidable-escaped-quote
"S101", # assert
"SIM108", # if-else-block-instead-of-if-exp
"TRY003", # raise-vanilla-args
"W191", # tab-indentation
]
# see https://docs.astral.sh/ruff/rules/ for rules documentation
select = [
"A", # flake8-builtins
"ARG", # flake8-unused-arguments
"A", # flake8-builtins
"ARG", # flake8-unused-arguments
"ASYNC", # flake8-async
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"E4", # pycodestyle
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"E4", # pycodestyle
"E7",
"E9",
"F", # pyflakes
"FA", # flake8-future-annotations
"FBT", # flake8-boolean-trap
"FLY", # flynt # "FURB", # refurb
"G", # flake8-logging-format
"I", # isort
"ICN", # flake8-import-conventions
"INT", # flake8-gettext
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"N", # pep8-naming
"NPY", # numpy
"Q", # flake8-quotes
"PERF", # perflint
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"PYI", # flake8-pyi
"RSE", # flake8-raise
"RUF", # ruff
"S", # flake8-bandit
"SIM", # flake8-simplify
"SLF", # flake8-self
"SLOT", # flake8-slots
"T10", # flake8-debugger
"T20", # flake8-print
"TCH", # flake8-type-checking
"TID", # flake8-tidy-imports
"TRY", # tryceratops
"UP", # pyupgrade
"F", # pyflakes
"FA", # flake8-future-annotations
"FBT", # flake8-boolean-trap
"FLY", # flynt # "FURB", # refurb
"G", # flake8-logging-format
"I", # isort
"ICN", # flake8-import-conventions
"INT", # flake8-gettext
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"N", # pep8-naming
"NPY", # numpy
"PERF", # perflint
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"PYI", # flake8-pyi
"Q", # flake8-quotes
"RSE", # flake8-raise
"RUF", # ruff
"S", # flake8-bandit
"SIM", # flake8-simplify
"SLF", # flake8-self
"SLOT", # flake8-slots
"T10", # flake8-debugger
"T20", # flake8-print
"TCH", # flake8-type-checking
"TID", # flake8-tidy-imports
"TRY", # tryceratops
"UP", # pyupgrade
"W6",
"YTT", # flake8-2020
"YTT", # flake8-2020
]

# Allow fix for all enabled rules (when `--fix`) is provided.
Expand All @@ -168,22 +178,12 @@ multiline-quotes = "double"
[tool.ruff.lint.isort]
combine-as-imports = true

[tool.pyright]
include = ["starlette_compress", "tests"]
pythonPlatform = "All"
pythonVersion = "3.8"

[tool.pytest.ini_options]
addopts = "-ra --quiet --disable-pytest-warnings"
minversion = "6.0"
testpaths = [
"tests",
]

[tool.mypy]
exclude = [
"tests",
]
ignore_missing_imports = true
python_version = "3.8"
strict = true
warn_no_return = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
warn_unused_ignores = true
testpaths = ["tests"]
39 changes: 22 additions & 17 deletions shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,48 @@

let
# Update packages with `nixpkgs-update` command
pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/ac82a513e55582291805d6f09d35b6d8b60637a1.tar.gz") { };
pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/9299cdf978e15f448cf82667b0ffdd480b44ee48.tar.gz") { };

pythonLibs = with pkgs; [
stdenv.cc.cc.lib
zlib.out
];

# Override LD_LIBRARY_PATH to load Python libraries
wrappedPython = with pkgs; symlinkJoin {
python' = with pkgs; symlinkJoin {
name = "python";
paths = [ python312 ];
paths = [ python313 ];
buildInputs = [ makeWrapper ];
postBuild = ''
wrapProgram "$out/bin/python3.12" --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath pythonLibs}"
wrapProgram "$out/bin/python3.13" --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath pythonLibs}"
'';
};

packages' = with pkgs; [
wrappedPython
coreutils
python'
poetry
ruff
fswatch
pyright
watchexec

(writeShellScriptBin "run-tests" ''
set -e
python -m pytest . --cov starlette_compress --cov-report xml
python -m mypy .
'')
(writeShellScriptBin "watch-tests" ''
run-tests || true
while fswatch -1 --latency 0.1 --event Updated --recursive --include "\.py$" .; do
run-tests || true
done
python -m pytest . \
--verbose \
--no-header \
--cov starlette_compress \
--cov-report "''${1:-xml}"
pyright
'')
(writeShellScriptBin "watch-tests" "watchexec --watch starlette_compress --watch tests --exts py run-tests")
(writeShellScriptBin "nixpkgs-update" ''
set -e
hash=$(git ls-remote https://github.com/NixOS/nixpkgs nixpkgs-unstable | cut -f 1)
hash=$(
curl --silent --location \
https://prometheus.nixos.org/api/v1/query \
-d "query=channel_revision{channel=\"nixpkgs-unstable\"}" | \
grep --only-matching --extended-regexp "[0-9a-f]{40}")
sed -i -E "s|/nixpkgs/archive/[0-9a-f]{40}\.tar\.gz|/nixpkgs/archive/$hash.tar.gz|" shell.nix
echo "Nixpkgs updated to $hash"
'')
Expand All @@ -47,11 +52,11 @@ let
shell' = with pkgs; lib.optionalString isDevelopment ''
current_python=$(readlink -e .venv/bin/python || echo "")
current_python=''${current_python%/bin/*}
[ "$current_python" != "${wrappedPython}" ] && rm -r .venv
[ "$current_python" != "${python'}" ] && rm -rf .venv/
echo "Installing Python dependencies"
export POETRY_VIRTUALENVS_IN_PROJECT=1
poetry env use "${wrappedPython}/bin/python"
poetry env use "${python'}/bin/python"
poetry install --compile
echo "Activating Python virtual environment"
Expand Down
4 changes: 2 additions & 2 deletions starlette_compress/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from starlette.datastructures import Headers, MutableHeaders
from zstandard import ZstdCompressor

if platform.python_implementation() == 'CPython':
if platform.python_implementation() == 'CPython' and not TYPE_CHECKING:
try:
import brotli
except ModuleNotFoundError:
Expand Down Expand Up @@ -216,7 +216,7 @@ async def wrapper(message: Message) -> None:

if not more_body:
# one-shot
compressed_body = brotli.compress(body, quality=self.quality)
compressed_body: bytes = brotli.compress(body, quality=self.quality)
headers['Content-Length'] = str(len(compressed_body))
message['body'] = compressed_body
await send(start_message)
Expand Down
Loading

0 comments on commit e99d6bb

Please sign in to comment.