Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ updates:
- "patch"
cooldown:
default-days: 7
- package-ecosystem: "cargo"
directories:
- "/packages/smithy-checksums"
schedule:
interval: "weekly"
day: "wednesday"
groups:
cargo:
update-types:
- "minor"
- "patch"
cooldown:
default-days: 7
- package-ecosystem: "gradle"
directory: "/codegen"
schedule:
Expand Down
154 changes: 154 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ jobs:
fail-fast: false
matrix:
python-version: ["3.12", "3.13", "3.14", "3.14t", "3.15"]
env:
# Fail rather than fall back to pure Python if a native extension can't be built.
SMITHY_PYTHON_NATIVE_BUILD: always

steps:
- name: Checkout Repository
Expand Down Expand Up @@ -49,6 +52,19 @@ jobs:
with:
version: 3.8.2

- name: Set up Rust
# Installs the toolchain pinned in rust-toolchain.toml.
run: |
rustup toolchain install

- name: Cache Rust builds
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: packages/smithy-checksums
key: ${{ matrix.python-version }}
# Pull requests restore the caches develop saves, without adding their own.
save-if: ${{ github.ref == 'refs/heads/develop' }}

- name: Setup workspace
run: |
make install
Expand All @@ -58,6 +74,17 @@ jobs:
run: |
make check-py

- name: Install Rust dependency tools
if: ${{ matrix.python-version == '3.12' }}
uses: taiki-e/install-action@1e29709c0ec63babbe8f266397a465f29a825f91 # v2.87.31
with:
tool: cargo-about@0.9.2,cargo-deny@0.20.2

- name: Check rust extensions
if: ${{ matrix.python-version == '3.12' }}
run: |
make check-rust

- name: Check API snapshot
if: ${{ matrix.python-version == '3.12' }}
run: |
Expand Down Expand Up @@ -88,3 +115,130 @@ jobs:
if: ${{ matrix.python-version == '3.12' }}
run: |
make typecheck-protocols

# Builds each native extension as a wheel on every platform and tests the
# installed wheel. The release pipeline builds the published wheels; this
# catches platform-specific build or test failures before then.
native-wheels:
name: Native wheels (${{ matrix.package }}, ${{ matrix.os }}, Python ${{ matrix.python-version }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest, windows-latest]
# 3.12 builds the abi3 wheel, 3.14t a version-specific free-threaded
# wheel, and 3.15t the abi3t wheel.
python-version: ["3.12", "3.14t", "3.15t"]
package: [smithy-checksums]
env:
SMITHY_PYTHON_NATIVE_BUILD: always
PACKAGE: ${{ matrix.package }}
defaults:
run:
shell: bash

steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Install uv and set the Python version
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
enable-cache: true

- name: Set up Rust
# Installs the toolchain pinned in rust-toolchain.toml.
run: |
rustup toolchain install

- name: Cache Rust builds
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: packages/${{ matrix.package }}
key: ${{ matrix.python-version }}
# Pull requests restore the caches develop saves, without adding their own.
save-if: ${{ github.ref == 'refs/heads/develop' }}

- name: Build wheel
run: |
uv build "packages/$PACKAGE" --wheel --out-dir dist

- name: Test wheel
run: |
uv pip install pytest dist/*.whl
python -c "import smithy_checksums; assert smithy_checksums.HAS_NATIVE_EXTENSION"
python -m pytest "packages/$PACKAGE/tests" --import-mode=importlib -o addopts=""

# Tests the pure-Python wheel, and installing from the sdist without a Rust
# toolchain, which should fall back to the same pure-Python build.
pure-python-fallback:
name: Pure-Python fallback (${{ matrix.package }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: [smithy-checksums]
env:
PACKAGE: ${{ matrix.package }}

steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Install uv and set the Python version
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
with:
python-version: "3.12"
activate-environment: true
enable-cache: true

- name: Build sdist and pure-Python wheel
env:
SMITHY_PYTHON_NATIVE_BUILD: never
run: |
uv build "packages/$PACKAGE" --out-dir dist

- name: Test pure-Python wheel
run: |
uv pip install pytest awscrt dist/*-py3-none-any.whl
python -c "import smithy_checksums; assert not smithy_checksums.HAS_NATIVE_EXTENSION"
python -m pytest "packages/$PACKAGE/tests" --import-mode=importlib -o addopts=""

- name: Test sdist install without Rust
run: |
PATH="$(echo "$PATH" | tr ':' '\n' | grep -v '/\.cargo/bin' | paste -sd: -)"
if command -v cargo; then echo "cargo is still on the PATH"; exit 1; fi
uv venv .venv-sdist
uv pip install --python .venv-sdist --no-cache pytest awscrt dist/*.tar.gz
.venv-sdist/bin/python -c "import smithy_checksums; assert not smithy_checksums.HAS_NATIVE_EXTENSION"
.venv-sdist/bin/python -m pytest "packages/$PACKAGE/tests" --import-mode=importlib -o addopts=""

# Checks each native extension builds with the minimum Rust version it declares,
# which source builds require.
rust-minimum-version:
name: Rust minimum version (${{ matrix.package }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: [smithy-checksums]
env:
PACKAGE: ${{ matrix.package }}

steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Check with the minimum Rust version
run: |
version="$(sed -n 's/^rust-version = "\(.*\)"$/\1/p' "packages/$PACKAGE/Cargo.toml")"
rustup toolchain install "$version" --profile minimal
cargo "+$version" check --manifest-path "packages/$PACKAGE/Cargo.toml" --locked --all-targets
3 changes: 3 additions & 0 deletions .licenserc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ header:

paths:
- '**/*.py'
- '**/*.pyi'
- '**/*.rs'

paths-ignore:
- '**/*.md'
Expand All @@ -22,3 +24,4 @@ header:
Python:
extensions:
- ".py"
- ".pyi"
38 changes: 37 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.DEFAULT_GOAL:=help

.PHONY: help install format-java check-java build-java test-protocols typecheck-protocols generate-protocol-tests generate-codegen-output-py api-snapshot aio-check ci lint-py check-py test-py test-integration benchmark build-py clean
.PHONY: help install format-java check-java build-java test-protocols typecheck-protocols generate-protocol-tests generate-codegen-output-py api-snapshot aio-check ci lint-py check-py lint-rust check-rust third-party-licenses test-py test-integration benchmark build-py clean

help: ## Show this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
Expand Down Expand Up @@ -94,8 +94,44 @@ check-py: ## Runs checks (formatting, lints, type-checking) on the python packag
uv run pyright packages


# Packages with a native extension, each built from a Cargo.toml in the package root.
RUST_MANIFESTS := $(wildcard packages/*/Cargo.toml)

lint-rust: ## Formats and fixes lints in the Rust extensions.
@set -e; for manifest in $(RUST_MANIFESTS); do \
cargo fmt --manifest-path "$$manifest"; \
cargo clippy --manifest-path "$$manifest" --all-targets --fix --allow-dirty --allow-staged; \
done


check-rust: ## Checks formatting, lints, dependencies, and license attribution of the Rust extensions.
@set -e; for manifest in $(RUST_MANIFESTS); do \
dir=$$(dirname "$$manifest"); \
cargo fmt --manifest-path "$$manifest" --check; \
cargo clippy --manifest-path "$$manifest" --all-targets --locked -- -D warnings; \
cargo deny --manifest-path "$$manifest" check; \
cargo about generate --manifest-path "$$manifest" \
--output-file "$$dir/LICENSE-THIRD-PARTY.expected" "$$dir/about.hbs"; \
if ! diff -u "$$dir/LICENSE-THIRD-PARTY" "$$dir/LICENSE-THIRD-PARTY.expected"; then \
rm "$$dir/LICENSE-THIRD-PARTY.expected"; \
echo "$$dir/LICENSE-THIRD-PARTY is out of date. Run 'make third-party-licenses'."; \
exit 1; \
fi; \
rm "$$dir/LICENSE-THIRD-PARTY.expected"; \
done


third-party-licenses: ## Regenerates the third-party license file of each Rust extension from its Cargo.lock.
@set -e; for manifest in $(RUST_MANIFESTS); do \
dir=$$(dirname "$$manifest"); \
cargo about generate --manifest-path "$$manifest" \
--output-file "$$dir/LICENSE-THIRD-PARTY" "$$dir/about.hbs"; \
done


ci: ## Runs the full CI sequence locally (mirrors the CI workflow steps).
make check-py
make check-rust
make api-snapshot
make test-py
make build-py
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "feature",
"description": "Added CRC32 and CRC32C checksums, backed by a native Rust extension with a pure-Python fallback, and SHA-1, SHA-256, SHA-512, and MD5 checksums through `new()`."
}
3 changes: 3 additions & 0 deletions packages/smithy-checksums/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Native extension built in place by editable installs.
*.so
*.pyd
1 change: 1 addition & 0 deletions packages/smithy-checksums/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Changelog
Loading
Loading