Skip to content

Commit f7326e7

Browse files
authored
Merge pull request #108 from labstreaminglayer/bundle_libs
Update to liblsl 1.17.4 and bundle libs on more targets
2 parents c90f623 + b07b3b2 commit f7326e7

7 files changed

Lines changed: 144 additions & 53 deletions

File tree

.github/workflows/ci.yml

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ on:
99
workflow_dispatch:
1010

1111
env:
12-
LSL_RELEASE_URL: "https://github.com/sccn/liblsl/releases/download/v1.16.2"
13-
LSL_RELEASE: "1.16.2"
12+
LSL_RELEASE_URL: "https://github.com/sccn/liblsl/releases/download/v1.17.4"
13+
LSL_RELEASE: "1.17.4"
1414

1515
jobs:
1616

@@ -19,10 +19,9 @@ jobs:
1919
runs-on: ubuntu-latest
2020
steps:
2121
- uses: actions/checkout@v4
22-
- uses: astral-sh/ruff-action@v1
23-
- uses: astral-sh/ruff-action@v1
24-
with:
25-
args: "format --check"
22+
- uses: astral-sh/setup-uv@v4
23+
- run: uv run ruff check
24+
- run: uv run ruff format --check
2625

2726
test:
2827
needs: style
@@ -37,16 +36,18 @@ jobs:
3736
- uses: actions/checkout@v4
3837
- name: Download liblsl (Windows)
3938
if: matrix.os == 'windows-latest'
39+
shell: bash
4040
run: |
41-
curl -L https://github.com/sccn/liblsl/releases/download/v1.16.2/liblsl-1.16.2-Win_amd64.zip -o liblsl.zip
42-
unzip -oj liblsl.zip bin/lsl* -d src/pylsl/lib/
41+
curl -L ${LSL_RELEASE_URL}/liblsl-${LSL_RELEASE}-Win_amd64.zip -o liblsl.zip
42+
unzip -oj liblsl.zip '*/bin/lsl.dll' -d src/pylsl/lib/
4343
- name: Install liblsl (MacOS)
4444
if: matrix.os == 'macos-latest'
45-
run: brew install labstreaminglayer/tap/lsl
45+
run: |
46+
brew install labstreaminglayer/tap/lsl
47+
echo "PYLSL_LIB=$(brew --prefix lsl)/Frameworks/lsl.framework/Versions/A/lsl" >> $GITHUB_ENV
4648
- name: Install liblsl (Ubuntu)
4749
if: startsWith(matrix.os, 'ubuntu-')
4850
run: |
49-
sudo apt install -y libpugixml-dev
5051
curl -L ${LSL_RELEASE_URL}/liblsl-${LSL_RELEASE}-$(lsb_release -sc)_amd64.deb -o liblsl.deb
5152
sudo apt install ./liblsl.deb
5253
- name: Install uv

.github/workflows/publish-to-pypi.yml

Lines changed: 125 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,151 @@ name: Build and publish Python 🐍 distributions 📦 to PyPI
33
on:
44
release:
55
types: [published]
6+
pull_request:
7+
branches:
8+
- main
69
workflow_dispatch:
710

811
env:
9-
LSL_RELEASE_URL: "https://github.com/sccn/liblsl/releases/download/"
10-
LSL_RELEASE: "1.16.2"
12+
LSL_RELEASE_URL: "https://github.com/sccn/liblsl/releases/download/v1.17.4"
13+
LSL_RELEASE: "1.17.4"
1114

1215
defaults:
1316
run:
1417
shell: bash
1518

1619
jobs:
17-
deploy:
18-
name: ${{ matrix.config.name }}
20+
# Build pure Python wheel (no bundled library) as fallback
21+
build-pure:
22+
name: Build pure Python wheel
23+
runs-on: ubuntu-latest
24+
steps:
25+
- uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0 # Needed for setuptools-scm
28+
- name: Install uv
29+
uses: astral-sh/setup-uv@v4
30+
- name: Build pure Python wheel
31+
run: uv build
32+
- name: Upload wheels
33+
uses: actions/upload-artifact@v4
34+
with:
35+
name: wheels-pure
36+
path: dist/*
37+
38+
# Build platform-specific wheels with bundled liblsl
39+
build-platform:
40+
name: Build ${{ matrix.config.name }}
1941
runs-on: ${{ matrix.config.os }}
20-
permissions:
21-
id-token: write
2242
strategy:
2343
fail-fast: false
2444
matrix:
2545
config:
26-
- name: "ubuntu-24.04"
27-
os: "ubuntu-latest"
28-
pyarch: "x64"
29-
- name: "windows-x64"
30-
os: "windows-latest"
31-
arch: "amd64"
32-
pyarch: "x64"
33-
- name: "windows-x86"
34-
os: "windows-latest"
35-
arch: "i386"
36-
pyarch: "x86"
46+
- name: "Windows x64"
47+
os: windows-latest
48+
arch: amd64
49+
pyarch: x64
50+
asset: "liblsl-${LSL_RELEASE}-Win_amd64.zip"
51+
extract: "unzip -oj liblsl.zip '*/bin/lsl.dll' -d src/pylsl/lib"
52+
- name: "Windows x86"
53+
os: windows-latest
54+
arch: i386
55+
pyarch: x86
56+
asset: "liblsl-${LSL_RELEASE}-Win_i386.zip"
57+
extract: "unzip -oj liblsl.zip '*/bin/lsl.dll' -d src/pylsl/lib"
58+
- name: "macOS universal"
59+
os: macos-latest
60+
arch: universal
61+
pyarch: x64
62+
asset: "lsl.xcframework.1.17.zip"
63+
extract: |
64+
unzip xcframework.zip
65+
cp lsl.xcframework/macos-arm64_x86_64/lsl.framework/Versions/A/lsl src/pylsl/lib/liblsl.dylib
66+
codesign -s - -f src/pylsl/lib/liblsl.dylib
67+
- name: "Linux x86_64"
68+
os: ubuntu-22.04
69+
arch: x86_64
70+
pyarch: x64
71+
asset: "liblsl-${LSL_RELEASE}-jammy_amd64.deb"
72+
extract: |
73+
sudo apt-get update && sudo apt-get install -y libpugixml1v5
74+
ar x liblsl.deb
75+
tar -xf data.tar.* --wildcards '*/liblsl.so*'
76+
cp ./usr/lib/liblsl.so* src/pylsl/lib/
77+
repair: true
3778
steps:
3879
- uses: actions/checkout@v4
39-
- name: Download liblsl (Windows)
40-
if: matrix.config.os == 'windows-latest'
80+
with:
81+
fetch-depth: 0 # Needed for setuptools-scm
82+
83+
- name: Download liblsl
84+
run: |
85+
ASSET="${{ matrix.config.asset }}"
86+
ASSET="${ASSET//\$\{LSL_RELEASE\}/$LSL_RELEASE}"
87+
if [[ "$ASSET" == *xcframework* ]]; then
88+
curl -L "${LSL_RELEASE_URL}/${ASSET}" -o xcframework.zip
89+
elif [[ "$ASSET" == *.zip ]]; then
90+
curl -L "${LSL_RELEASE_URL}/${ASSET}" -o liblsl.zip
91+
elif [[ "$ASSET" == *.deb ]]; then
92+
curl -L "${LSL_RELEASE_URL}/${ASSET}" -o liblsl.deb
93+
else
94+
curl -L "${LSL_RELEASE_URL}/${ASSET}" -o liblsl.tar.gz
95+
fi
96+
97+
- name: Extract liblsl
4198
run: |
42-
curl -L ${LSL_RELEASE_URL}/v${LSL_RELEASE}/liblsl-${LSL_RELEASE}-Win_${{ matrix.config.arch}}.zip -o liblsl.zip
43-
unzip -oj liblsl.zip bin/lsl* -d src/pylsl/lib
44-
- name: Set up Python 3.x
45-
uses: actions/setup-python@v4
99+
mkdir -p src/pylsl/lib
100+
${{ matrix.config.extract }}
101+
102+
- name: List bundled library
103+
run: ls -la src/pylsl/lib/
104+
105+
- name: Set up Python
106+
uses: actions/setup-python@v5
46107
with:
47108
python-version: "3.x"
48109
architecture: ${{ matrix.config.pyarch }}
110+
49111
- name: Install uv
50112
uses: astral-sh/setup-uv@v4
51-
- name: Build Package (Linux)
52-
if: matrix.config.os != 'windows-latest'
53-
run: uv build
54-
- name: Build Package (Windows)
55-
if: matrix.config.os == 'windows-latest'
113+
114+
- name: Build wheel
56115
run: uv build --wheel
57-
- name: Publish package distributions to PyPI
58-
run: uv publish
116+
117+
- name: Repair wheel (Linux)
118+
if: matrix.config.repair
119+
run: |
120+
pip install auditwheel patchelf
121+
auditwheel repair dist/*.whl -w dist/
122+
rm dist/*-none-any.whl
123+
124+
- name: Upload wheels
125+
uses: actions/upload-artifact@v4
126+
with:
127+
name: wheels-${{ matrix.config.os }}-${{ matrix.config.arch }}
128+
path: dist/*.whl
129+
130+
# Publish all wheels to PyPI
131+
publish:
132+
name: Publish to PyPI
133+
needs: [build-pure, build-platform]
134+
runs-on: ubuntu-latest
135+
permissions:
136+
id-token: write
137+
steps:
138+
- name: Download all wheels
139+
uses: actions/download-artifact@v4
140+
with:
141+
path: dist
142+
pattern: wheels-*
143+
merge-multiple: true
144+
145+
- name: List wheels
146+
run: ls -la dist/
147+
148+
- name: Install uv
149+
uses: astral-sh/setup-uv@v4
150+
151+
- name: Publish to PyPI
152+
if: github.event_name == 'release'
153+
run: uv publish dist/*

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ examples = [
5151
[dependency-groups]
5252
dev = [
5353
"pytest>=8.3.4",
54-
"ruff>=0.8.2",
54+
"ruff>=0.14",
5555
]
5656

5757
[build-system]
@@ -65,4 +65,4 @@ license-files = []
6565
version_file = "src/pylsl/__version__.py"
6666

6767
[tool.setuptools.package-data]
68-
pylsl = ["lib/*.dll"]
68+
pylsl = ["lib/*.dll", "lib/*.so*", "lib/*.dylib"]

src/pylsl/info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def __init__(
9292
)
9393
self.obj = ctypes.c_void_p(self.obj)
9494
if not self.obj:
95-
raise RuntimeError("could not create stream description " "object.")
95+
raise RuntimeError("could not create stream description object.")
9696

9797
def __del__(self):
9898
"""Destroy a previously created StreamInfo object."""

src/pylsl/inlet.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,7 @@ def __init__(
5858
flags. Use `proc_ALL` for all flags. (default proc_none).
5959
"""
6060
if type(info) is list:
61-
raise TypeError(
62-
"description needs to be of type StreamInfo, " "got a list."
63-
)
61+
raise TypeError("description needs to be of type StreamInfo, got a list.")
6462
self.obj = lib.lsl_create_inlet(info.obj, max_buflen, max_chunklen, recover)
6563
self.obj = ctypes.c_void_p(self.obj)
6664
if not self.obj:

src/pylsl/lib/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,14 +257,14 @@ def find_liblsl_libraries(verbose=False):
257257
lib.lsl_pull_chunk_str.restype = ctypes.c_long
258258
lib.lsl_pull_chunk_buf.restype = ctypes.c_long
259259
except Exception:
260-
print("pylsl: chunk transfer functions not available in your liblsl " "version.")
260+
print("pylsl: chunk transfer functions not available in your liblsl version.")
261261
# noinspection PyBroadException
262262
try:
263263
lib.lsl_create_continuous_resolver.restype = ctypes.c_void_p
264264
lib.lsl_create_continuous_resolver_bypred.restype = ctypes.c_void_p
265265
lib.lsl_create_continuous_resolver_byprop.restype = ctypes.c_void_p
266266
except Exception:
267-
print("pylsl: ContinuousResolver not (fully) available in your liblsl " "version.")
267+
print("pylsl: ContinuousResolver not (fully) available in your liblsl version.")
268268

269269

270270
# int64 support on windows and 32bit OSes isn't there yet

src/pylsl/util.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ def deprecated(reason: str = None):
122122
def old_function():
123123
pass
124124
"""
125+
125126
def decorator(func):
126127
message = f"Function '{func.__name__}' is deprecated."
127128
if reason:
@@ -130,11 +131,7 @@ def decorator(func):
130131
@functools.wraps(func)
131132
def wrapper(*args, **kwargs):
132133
warnings.simplefilter("always", DeprecationWarning) # ensure it shows up
133-
warnings.warn(
134-
message,
135-
category=DeprecationWarning,
136-
stacklevel=2
137-
)
134+
warnings.warn(message, category=DeprecationWarning, stacklevel=2)
138135
warnings.simplefilter("default", DeprecationWarning)
139136
return func(*args, **kwargs)
140137

0 commit comments

Comments
 (0)