Skip to content

docs: Update projects #46

docs: Update projects

docs: Update projects #46

# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
name: Build cchardet wheels (riscv64)
on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/cchardet.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-cchardet.yml'
- 'docs/packages/cchardet.yaml'
push:
branches: [main]
paths:
- '.github/workflows/build-cchardet.yml'
- 'docs/packages/cchardet.yaml'
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read # to fetch code (actions/checkout)
env:
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: cchardet
version: ${{ inputs.version }}
build_sdist:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build cchardet ${{ matrix.version }} sdist
runs-on: ubuntu-latest
env:
CCHARDET_VERSION: ${{ matrix.version }}
steps:
# Upstream tagged releases bare up to 2.1.7 and v-prefixed from 2.2.0 on.
- name: Resolve the cChardet tag
id: tag
run: |
for ref in "v$CCHARDET_VERSION" "$CCHARDET_VERSION"; do
if git ls-remote --exit-code --tags https://github.com/PyYoshi/cChardet "refs/tags/$ref" >/dev/null; then
echo "name=$ref" >> "$GITHUB_OUTPUT"
exit 0
fi
done
echo "::error::PyYoshi/cChardet has no tag for $CCHARDET_VERSION"
exit 1
- name: Checkout cChardet ${{ env.CCHARDET_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: PyYoshi/cChardet
ref: ${{ steps.tag.outputs.name }}
submodules: recursive
persist-credentials: false
- name: Install Python
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: '3.12'
activate-environment: true
enable-cache: false
- name: Build sdist
id: sdist
# This tag ships no pyproject.toml: setup.py cythonises _cchardet.pyx
# itself whenever Cython is importable, so Cython has to be
# preinstalled with isolation off, or the bundled .cpp is whatever a
# bare `setuptools`+`wheel` env leaves behind (nothing, in practice).
run: |
uv pip install cython setuptools wheel build twine
python -m build --sdist --no-isolation
twine check dist/*
- name: Upload sdist artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: cchardet-${{ env.CCHARDET_VERSION }}-sdist
path: dist/*.tar.gz
if-no-files-found: error
build_wheels:
needs: [setup, build_sdist]
if: needs.setup.outputs.versions != '[]'
name: Build cchardet ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
python: ["cp312", "cp313", "cp314", "cp314t"]
env:
CCHARDET_VERSION: ${{ matrix.version }}
steps:
- name: Download sdist
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: cchardet-${{ env.CCHARDET_VERSION }}-sdist
path: dist/
- name: Extract sdist and stage the wheel smoke test
# Upstream's own cibuildwheel config (test-command/test-sources in
# pyproject.toml) runs tools/wheel_smoke.py, but MANIFEST.in doesn't
# ship tools/ in the sdist, so this reproduces that same script here.
run: |
mkdir pkg
tar xzf dist/*.tar.gz --strip-components=1 -C pkg
cat > pkg/riscv64_test_cchardet.py <<'EOF'
import json
import os
import subprocess
import sys
import sysconfig
import tempfile
from pathlib import Path
import cchardet
def main() -> None:
# Upstream only added this assertion in tools/wheel_smoke.py starting at
# v2.3.0; v2.2.0's _cchardet extension doesn't declare free-threading
# support, so CPython 3.14t legitimately re-enables the GIL on import.
version = tuple(int(p) for p in os.environ["CCHARDET_VERSION"].split("."))
if sysconfig.get_config_var("Py_GIL_DISABLED") and version >= (2, 3, 0):
assert not getattr(sys, "_is_gil_enabled")()
package_dir = Path(cchardet.__file__).parent
assert (package_dir / "py.typed").is_file()
assert (package_dir / "_cchardet.pyi").is_file()
expected = cchardet.detect(b"plain ASCII")
assert expected["encoding"] == "ASCII"
assert cchardet.detect(bytearray(b"plain ASCII")) == expected
assert cchardet.detect(memoryview(b"plain ASCII"), max_bytes=32) == expected
french = ("Français, où êtes-vous ? Voilà l'été.").encode(
"windows-1252"
)
candidates = cchardet.detect_all(french)
assert candidates
assert candidates[0] == cchardet.detect(french)
assert candidates[0]["language"] == "fr"
detector = cchardet.UniversalDetector()
detector.feed(french[:10])
detector.feed(french[10:])
detector.close()
assert detector.result == candidates[0]
with tempfile.TemporaryDirectory() as directory:
sample = Path(directory) / "sample.txt"
sample.write_bytes(french)
output = subprocess.check_output(
[sys.executable, "-m", "cchardet", "--json", str(sample)],
text=True,
)
assert json.loads(output)["language"] == "fr"
if __name__ == "__main__":
main()
EOF
- name: Build and test wheels
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
package-dir: pkg
output-dir: wheelhouse/
only: ${{ matrix.python }}-manylinux_riscv64
env:
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
# CIBW_TEST_SOURCES is relative to the cwd, not package-dir, hence "pkg/".
CIBW_TEST_SOURCES: pkg/riscv64_test_cchardet.py
CIBW_TEST_COMMAND: python pkg/riscv64_test_cchardet.py
# A job-level `env:` never reaches the Linux container (gotcha 129), so the
# test script's os.environ["CCHARDET_VERSION"] read needs it via CIBW_ENVIRONMENT.
CIBW_ENVIRONMENT: CCHARDET_VERSION=${{ env.CCHARDET_VERSION }}
- name: Verify the wheel ships the compiled extension
run: |
python3 - wheelhouse/*.whl <<'EOF'
import sys, zipfile
names = zipfile.ZipFile(sys.argv[1]).namelist()
assert any(n.startswith("cchardet/_cchardet") and n.endswith(".so") for n in names), names
assert any(n.endswith(".dist-info/licenses/COPYING") for n in names), names
print("ok")
EOF
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: cchardet-${{ matrix.version }}-${{ matrix.python }}-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error
publish:
name: Publish cchardet ${{ matrix.version }}
needs: [setup, build_sdist, build_wheels]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
secrets:
app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }}
with:
artifact-pattern: cchardet-${{ matrix.version }}-*-manylinux_riscv64