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
77 changes: 66 additions & 11 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ on:
push:
branches:
- master
tags:
- 'v*'
pull_request:
types:
- opened
Expand All @@ -13,10 +15,14 @@ jobs:
build-and-test:
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]

include: # Used to choose which version of Python to use for docs and for sdist
- python-version: "3.12"
canonical: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7


- name: git setup
Expand All @@ -42,12 +48,18 @@ jobs:
# with pip to make sure it works.
run: |
source "${HOME}/conda/etc/profile.d/conda.sh"
conda create -p ./cython-env -y "cython>3.0" python=${{ matrix.python-version }} gxx zlib setuptools --channel conda-forge
conda create -p ./cython-env -y "cython>3.0" python=${{ matrix.python-version }} gxx zlib setuptools xz --channel conda-forge
conda activate ./cython-env
python setup.py clean cythonize sdist
(cd dist && pip install pybedtools-*.tar.gz && cd $TMPDIR && python -c 'import pybedtools; print(pybedtools.__file__)')
conda deactivate

- name: upload sdist
if: matrix.canonical
uses: actions/upload-artifact@v7
with:
name: sdist
path: dist/pybedtools-*.tar.gz

- name: conda env and install locally
# Set up conda and install pybedtools into that env
Expand Down Expand Up @@ -106,7 +118,7 @@ jobs:


- name: build-docs
if: ${{ (matrix.python-version == 3.10) }}
if: matrix.canonical
# Build docs and commit to gh-pages branch. Note that no push happens
# unless we're on the master branch
run: |
Expand All @@ -117,17 +129,29 @@ jobs:
cd /tmp/pybedtools-uncompressed/pybedtools-*
(cd docs && make html)

git clone \
--single-branch \
--branch gh-pages "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY" \
/tmp/docs
REPO_URL="https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY"

# The gh-pages branch may not exist upstream (e.g. in a fork that has
# never published docs); if so, create a new orphan branch to work in.
if git ls-remote --exit-code --heads "$REPO_URL" gh-pages > /dev/null 2>&1; then
git clone \
--single-branch \
--branch gh-pages "$REPO_URL" \
/tmp/docs
else
echo "gh-pages branch not found upstream; creating an orphan branch locally"
git clone "$REPO_URL" /tmp/docs
git -C /tmp/docs checkout --orphan gh-pages
git -C /tmp/docs rm -rf --quiet . || true
fi

rm -rf /tmp/docs/*
cp -r docs/build/html/* /tmp/docs
touch /tmp/docs/.nojekyll
cd /tmp/docs
git add .
if git diff --cached --quiet; then
# with --verify HEAD, if there's no HEAD then we should commit
if git rev-parse --verify HEAD > /dev/null 2>&1 && git diff --cached --quiet; then
echo "no changes, nothing to commit"
else
git commit -m 'update docs'
Expand All @@ -137,16 +161,47 @@ jobs:

- name: docs artifact
# Upload built docs as an artifact for inspection, even on PRs
uses: actions/upload-artifact@v4
if: matrix.canonical
uses: actions/upload-artifact@v7
with:
name: docs
path: /tmp/docs


- name: push docs to gh-pages branch
# Push docs to gh-pages if this test is running on master branch
if: ${{ (github.ref == 'refs/heads/master') && (matrix.python-version == 3.10) }}
if: (github.ref == 'refs/heads/master') && matrix.canonical
run: |
cd /tmp/docs
git push "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY" gh-pages
cd $WORKDIR


build-wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
cibw_archs: "x86_64"
- os: ubuntu-24.04-arm
cibw_archs: "aarch64"
- os: macos-latest
cibw_archs: "arm64 x86_64"

steps:
- uses: actions/checkout@v7

- name: Build wheels
uses: pypa/cibuildwheel@v4.2.0
env:
CIBW_ARCHS: ${{ matrix.cibw_archs }}
CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-* cp314-*"
CIBW_SKIP: "*-win*"
CIBW_BEFORE_BUILD: "pip install 'cython>3.0' setuptools && python setup.py cythonize"

- uses: actions/upload-artifact@v7
with:
name: wheels-${{ matrix.os }}
path: ./wheelhouse/*.whl
20 changes: 18 additions & 2 deletions pybedtools/test/test_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pathlib import Path
import pytest
import psutil
import gc

from pybedtools import filenames

Expand Down Expand Up @@ -61,14 +62,29 @@ def test_issue_81():

def test_issue_118():
p = psutil.Process(os.getpid())
start_fds = p.num_fds()
a = pybedtools.example_bedtool("a.bed")
b = pybedtools.example_bedtool("b.bed")

# p.num_fds() counts anything running on the machine. Recently (Aug 2026),
# some GitHub Actions tests failed the start == stop fds because we had
# *fewer* fds. This could occur from things outside of pytest that we can't
# control cleaning up fds. The big thing we're checking here is that we
# don't leak fds during this individual test.
#
# To make this a more accurate test, do a warm-up intersection field count,
# then garbage collect, then do the loop, then garbage collect again.
a.intersect(b).field_count()
gc.collect()
start_fds = p.num_fds()
for i in range(100):
c = a.intersect(b)
c.field_count()
gc.collect()

stop_fds = p.num_fds()
assert start_fds == stop_fds

# Could have had GC run
assert p.num_fds() <= start_fds


def test_issue_131():
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@

MAJ = 0
MIN = 12
REV = 0
VERSION = '%d.%d.%d' % (MAJ, MIN, REV)
REV = '1a'
VERSION = f'{MAJ}.{MIN}.{REV}'


class CleanCommand(Command):
Expand Down
Loading