docs: Update projects #9
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-FileCopyrightText: 2026 The RISE Project | |
| # SPDX-License-Identifier: MIT | |
| --- | |
| # This workflow is based on: https://github.com/tfmoraes/python-gdcm/blob/v3.2.6/.github/workflows/wheels.yml | |
| name: Build python-gdcm wheels (riscv64) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version glob to (re)build; empty builds every version of docs/packages/python-gdcm.yaml not released yet' | |
| required: false | |
| default: '' | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - '.github/workflows/build-python-gdcm.yml' | |
| - 'docs/packages/python-gdcm.yaml' | |
| push: | |
| branches: [main] | |
| paths: | |
| - '.github/workflows/build-python-gdcm.yml' | |
| - 'docs/packages/python-gdcm.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: python-gdcm | |
| version: ${{ inputs.version }} | |
| build_wheels: | |
| needs: [setup] | |
| if: needs.setup.outputs.versions != '[]' | |
| name: Build python-gdcm ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 | |
| runs-on: ubuntu-24.04-riscv | |
| timeout-minutes: 360 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| version: ${{ fromJSON(needs.setup.outputs.versions) }} | |
| python: | |
| - "cp312" | |
| - "cp313" | |
| - "cp314" | |
| - "cp314t" | |
| env: | |
| PYTHON_GDCM_VERSION: ${{ matrix.version }} | |
| steps: | |
| - name: Checkout python-gdcm ${{ env.PYTHON_GDCM_VERSION }} | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| repository: tfmoraes/python-gdcm | |
| ref: v${{ env.PYTHON_GDCM_VERSION }} | |
| submodules: true | |
| persist-credentials: false | |
| - name: Checkout python-wheels | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| path: python-wheels | |
| persist-credentials: false | |
| - name: Apply patches | |
| run: git apply -v python-wheels/patches/python-gdcm/${{ env.PYTHON_GDCM_VERSION }}/*.patch | |
| - name: Write the wheel test | |
| run: | | |
| cat > test_python_gdcm.py <<'EOF' | |
| import importlib.metadata | |
| import os | |
| import subprocess | |
| import tempfile | |
| import gdcm | |
| assert gdcm.Version.GetVersion() == "${{ env.PYTHON_GDCM_VERSION }}", gdcm.Version.GetVersion() | |
| assert gdcm.Global.GetInstance().GetDicts().GetDictEntry( | |
| gdcm.Tag(0x0010, 0x0010)).GetName() == "Patient's Name" | |
| licenses = sorted( | |
| str(f) for f in importlib.metadata.files("python-gdcm") if "/licenses/" in str(f)) | |
| assert len(licenses) == 13, licenses | |
| assert any(f.endswith("/licenses/LICENSE.openssl") for f in licenses), licenses | |
| WIDTH = HEIGHT = 64 | |
| PIXELS = bytes(bytearray(((x * 3 + y * 5) % 256) for y in range(HEIGHT) for x in range(WIDTH))) | |
| def buffer_of(image): | |
| return image.GetBuffer().encode("utf-8", "surrogateescape") | |
| with tempfile.TemporaryDirectory() as directory: | |
| writer = gdcm.ImageWriter() | |
| image = writer.GetImage() | |
| image.SetNumberOfDimensions(2) | |
| image.SetDimension(0, WIDTH) | |
| image.SetDimension(1, HEIGHT) | |
| pixel_format = gdcm.PixelFormat() | |
| pixel_format.SetScalarType(gdcm.PixelFormat.UINT8) | |
| image.SetPixelFormat(pixel_format) | |
| image.SetPhotometricInterpretation( | |
| gdcm.PhotometricInterpretation(gdcm.PhotometricInterpretation.MONOCHROME2)) | |
| pixeldata = gdcm.DataElement(gdcm.Tag(0x7fe0, 0x0010)) | |
| pixeldata.SetByteStringValue(PIXELS) | |
| image.SetDataElement(pixeldata) | |
| path = os.path.join(directory, "raw.dcm") | |
| writer.SetFileName(path) | |
| writer.SetImage(image) | |
| assert writer.Write() | |
| reader = gdcm.ImageReader() | |
| reader.SetFileName(path) | |
| assert reader.Read() | |
| assert reader.GetImage().GetDimension(0) == WIDTH | |
| assert reader.GetImage().GetDimension(1) == HEIGHT | |
| assert buffer_of(reader.GetImage()) == PIXELS | |
| for name in ("DeflatedExplicitVRLittleEndian", "RLELossless", | |
| "JPEGLSLossless", "JPEG2000Lossless"): | |
| change = gdcm.ImageChangeTransferSyntax() | |
| change.SetTransferSyntax(gdcm.TransferSyntax(getattr(gdcm.TransferSyntax, name))) | |
| change.SetInput(reader.GetImage()) | |
| assert change.Change(), name | |
| compressed = os.path.join(directory, name + ".dcm") | |
| encoder = gdcm.ImageWriter() | |
| encoder.SetFileName(compressed) | |
| encoder.SetImage(change.GetOutput()) | |
| assert encoder.Write(), name | |
| decoder = gdcm.ImageReader() | |
| decoder.SetFileName(compressed) | |
| assert decoder.Read(), name | |
| assert buffer_of(decoder.GetImage()) == PIXELS, name | |
| print(name, "ok") | |
| gdcmdump = os.path.join(os.path.dirname(gdcm.__file__), "_gdcm", "gdcmdump") | |
| dump = subprocess.run( | |
| [gdcmdump, path], check=True, capture_output=True, text=True).stdout | |
| assert "(7fe0,0010)" in dump, dump | |
| EOF | |
| - name: Build wheels | |
| uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 | |
| with: | |
| output-dir: wheelhouse/ | |
| only: ${{ matrix.python }}-manylinux_riscv64 | |
| env: | |
| CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} | |
| CIBW_BUILD_FRONTEND: build | |
| # Rocky 10's swig 4.3 replaces upstream's from-source SWIG 4.3.1 build. | |
| # The image's own /usr/local/bin/swig is 4.5.0, which dropped the | |
| # Python 2 compatibility macros GDCM's typemaps still use, so the | |
| # generated wrapper does not compile with it. | |
| CIBW_BEFORE_ALL: >- | |
| dnf -y install openssl-devel swig && | |
| cp /usr/share/licenses/openssl-libs/LICENSE.txt {project}/LICENSE.openssl | |
| # -fPIE/-pie: the image's GCC links executables at 0x10000, and the RPATH | |
| # patchelf writes during auditwheel repair then grows the first segment | |
| # below mmap_min_addr, so every gdcm* application segfaults at exec. The | |
| # compiler flag is what keeps CMake's own ABI detection linking. | |
| # cmake and ninja have no riscv64 wheel on public PyPI; PIP_ONLY_BINARY | |
| # keeps pip from source-building a newer one than our registry's. | |
| CIBW_ENVIRONMENT: >- | |
| CMAKE_ARGS="-DGDCM_USE_SYSTEM_OPENSSL:BOOL=ON -DSWIG_EXECUTABLE=/usr/bin/swig -DCMAKE_C_FLAGS=-fPIE -DCMAKE_CXX_FLAGS=-fPIE -DCMAKE_EXE_LINKER_FLAGS=-pie" | |
| PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ | |
| PIP_ONLY_BINARY=cmake,ninja | |
| CIBW_TEST_SOURCES: test_python_gdcm.py | |
| CIBW_TEST_COMMAND: python test_python_gdcm.py | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: python-gdcm-${{ env.PYTHON_GDCM_VERSION }}-${{ matrix.python }}-manylinux_riscv64 | |
| path: wheelhouse/*.whl | |
| if-no-files-found: error | |
| publish: | |
| name: Publish python-gdcm ${{ matrix.version }} | |
| needs: [setup, 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: python-gdcm-${{ matrix.version }}-*-manylinux_riscv64 |