Skip to content
Merged
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
129 changes: 129 additions & 0 deletions .github/workflows/build-ta-lib.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on: https://github.com/ta-lib/ta-lib-python/blob/v0.7.1/.github/workflows/wheels.yml
name: Build ta-lib wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'ta-lib version to build (git tag without leading v, e.g. 0.7.1)'
required: true
default: '0.7.1'
pull_request:
paths:
- '.github/workflows/build-ta-lib.yml'
- 'patches/ta-lib/**'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '0.7.1' }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
# `inputs.version` is empty on pull_request events; default to 0.7.1 there.
TA_LIB_VERSION: ${{ inputs.version || '0.7.1' }}
# The TA-Lib C library version fetched by tools/build_talib_linux.sh; a
# separate pin from TA_LIB_VERSION, mirroring upstream's own workflow.
TALIB_C_VER: '0.7.1'
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

jobs:
setup:
uses: $/.github/workflows/_setup.yml

build_wheels:
needs: [setup]
name: Build ta-lib ${{ inputs.version || '0.7.1' }} ${{ matrix.python }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
# Upstream's own CIBW_SKIP excludes cp313t/cp314t; the extension
# isn't declared free-threading safe.
python: ["cp312", "cp313", "cp314"]

steps:
- name: Checkout ta-lib-python v${{ env.TA_LIB_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ta-lib/ta-lib-python
ref: v${{ env.TA_LIB_VERSION }}
persist-credentials: false

- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false

- name: Patch ta-lib-python source
run: git apply python-wheels/patches/ta-lib/${{ env.TA_LIB_VERSION }}/*.patch

- 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_ENVIRONMENT_PASS_LINUX: TALIB_C_VER CFLAGS
CFLAGS: -D_GNU_SOURCE
CIBW_BEFORE_ALL_LINUX: |
curl -fsSL -o talib-$TALIB_C_VER.tar.gz https://github.com/TA-Lib/ta-lib/archive/refs/tags/v$TALIB_C_VER.tar.gz
mkdir -p ta-lib-$TALIB_C_VER
tar xzf talib-$TALIB_C_VER.tar.gz --strip-components=1 -C ta-lib-$TALIB_C_VER
cd ta-lib-$TALIB_C_VER
mkdir -p include/ta-lib/
cp include/*.h include/ta-lib/
cmake -S . -B _build -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/project/ta-lib-install
cmake --build _build -j"$(nproc)"
cmake --install _build
cp LICENSE /project/LICENSE.ta-lib-c
CIBW_ENVIRONMENT_LINUX: >-
TA_LIBRARY_PATH=/project/ta-lib-install/lib
TA_INCLUDE_PATH=/project/ta-lib-install/include
PIP_NO_BUILD_ISOLATION=false
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
PIP_ONLY_BINARY=numpy,pandas
CIBW_REPAIR_WHEEL_COMMAND_LINUX: |
LD_LIBRARY_PATH="/project/ta-lib-install/lib:$LD_LIBRARY_PATH" auditwheel repair -w {dest_dir} {wheel}
CIBW_BUILD_FRONTEND: build
CIBW_TEST_REQUIRES: pytest pandas
# test_polars.py imports polars unconditionally; no riscv64 polars
# wheel exists on PyPI or our registry to install it with.
CIBW_TEST_COMMAND: >-
cd .. &&
pytest -k "not RSI and not threading" --ignore={project}/tests/test_polars.py {project}/tests

- name: Check the wheel ships the extension and both licences
run: |
python3 - wheelhouse/*.whl <<'EOF'
import sys, zipfile
for whl in sys.argv[1:]:
names = zipfile.ZipFile(whl).namelist()
assert any(n.startswith("talib/") and n.endswith(".so") for n in names), whl
licences = {n.rsplit("/", 1)[1] for n in names if ".dist-info/licenses/" in n} - {""}
assert licences == {"LICENSE", "LICENSE.ta-lib-c"}, (whl, licences)
print(whl, "ok")
EOF

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ta-lib-${{ env.TA_LIB_VERSION }}-${{ matrix.python }}-manylinux_riscv64
path: ./wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish ta-lib ${{ inputs.version || '0.7.1' }}
needs: [setup, build_wheels]
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
with:
artifact-pattern: ta-lib-${{ inputs.version || '0.7.1' }}-*-manylinux_riscv64
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
From a041ab3466109942a11a2e857d85eda50e57b45b Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 7 Sep 2026 03:46:48 +0200
Subject: [PATCH] Widen license-files to cover the vendored TA-Lib C licence

license-files = ["LICENSE"] is an explicit PEP 639 list, so it replaces
setuptools' default LICEN[CS]E* glob rather than adding to it. The Linux,
macOS and Windows wheels dynamically link libta-lib, built from the
TA-Lib C library release that tools/build_talib_linux.sh (and its macOS/
Windows equivalents) downloads at build time from TA-Lib/ta-lib, which is
licensed under the 3-clause BSD licence whose clause 2 requires the
copyright notice to be reproduced in binary redistributions -- but the
built wheel ships only ta-lib-python's own LICENSE.

Widening the list to also match LICENSE.* lets a LICENSE.ta-lib-c dropped
at the project root reach dist-info/licenses/ with no other packaging
change.

Upstream-Status: To upstream [not yet submitted; the same gap exists in every ta-lib wheel on PyPI, so this needs a maintainer discussion rather than a drive-by PR]

Signed-off-by: Ludovic Henry <git@ludovic.dev>
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyproject.toml b/pyproject.toml
index dce4d7d..f609395 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,7 +7,7 @@ name = "TA-Lib"
version = "0.7.1"
description = "Python wrapper for TA-Lib"
readme = "README.md"
-license-files = ["LICENSE"]
+license-files = ["LICENSE", "LICENSE.*"]
authors = [
{name = "John Benediktsson", email = "mrjbq7@gmail.com"}
]
--
2.50.1 (Apple Git-155)