From 6de341ccce378ace92a5d3391543fdee77e79142 Mon Sep 17 00:00:00 2001 From: Li Yao Date: Fri, 26 Apr 2024 16:01:05 -0400 Subject: [PATCH 01/16] Add support for csi index --- pybedtools/bedtool.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/pybedtools/bedtool.py b/pybedtools/bedtool.py index 1b8b491d..11ebcf72 100644 --- a/pybedtools/bedtool.py +++ b/pybedtools/bedtool.py @@ -700,7 +700,11 @@ def tabix_intervals(self, interval_or_string, check_coordinates=False): # tabix expects 1-based coords, but BEDTools works with # zero-based. pybedtools and pysam also work with zero-based. So we can # pass zero-based directly to the pysam tabix interface. - tbx = pysam.TabixFile(self.fn) + try: + tbx = pysam.TabixFile(self.fn) + except OSError: + # if the file is indexed using csi, we need to specify the path for index + tbx = pysam.TabixFile(self.fn, index=self.fn+".csi") # If an interval is passed, use its coordinates directly if isinstance(interval_or_string, Interval): @@ -749,10 +753,14 @@ def tabix_contigs(self): "-- please use the .tabix() method" ) - tbx = pysam.TabixFile(self.fn) + try: + tbx = pysam.TabixFile(self.fn) + except OSError: + # if the file is indexed using csi, we need to specify the path for index + tbx = pysam.TabixFile(self.fn, index=self.fn+".csi") return tbx.contigs - def tabix(self, in_place=True, force=False, is_sorted=False): + def tabix(self, in_place=True, force=False, is_sorted=False, use_csi=False): """ Prepare a BedTool for use with Tabix. @@ -773,6 +781,10 @@ def tabix(self, in_place=True, force=False, is_sorted=False): is_sorted : bool If True (default is False), then assume the file is already sorted so that BedTool.bgzip() doesn't have to do that work. + + use_csi : bool + If True (default is False), then generate csi instead of tbi index. + This can be useful when working with chromosomes larger than 512 Mbp, such as barley """ # Return quickly if nothing to do if self._tabixed() and not force: @@ -781,18 +793,18 @@ def tabix(self, in_place=True, force=False, is_sorted=False): # Make sure it's BGZIPed fn = self.bgzip(in_place=in_place, force=force) - pysam.tabix_index(fn, force=force, preset=self.file_type) + pysam.tabix_index(fn, force=force, preset=self.file_type, csi=use_csi) return BedTool(fn) def _tabixed(self): """ Verifies that we're working with a tabixed file: a string filename - pointing to a BGZIPed file with a .tbi file in the same dir. + pointing to a BGZIPed file with a .tbi or .csi file in the same dir. """ if ( isinstance(self.fn, str) and isBGZIP(self.fn) - and os.path.exists(self.fn + ".tbi") + and (os.path.exists(self.fn + ".tbi") or os.path.exists(self.fn + ".csi")) ): return True From 970175d666653563e7561c8f6f858cbc43bd8c8a Mon Sep 17 00:00:00 2001 From: liyao001 Date: Fri, 26 Apr 2024 23:26:05 -0400 Subject: [PATCH 02/16] Extended original test case for `tabix` by testing both tbi and csi indexes --- pybedtools/test/test_1.py | 55 ++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/pybedtools/test/test_1.py b/pybedtools/test/test_1.py index b9d67fe5..54292ee1 100644 --- a/pybedtools/test/test_1.py +++ b/pybedtools/test/test_1.py @@ -133,35 +133,36 @@ def test_tuple_creation(): def test_tabix(): - try: - a = pybedtools.example_bedtool("a.bed") - t = a.tabix(force=True) - assert t._tabixed() - results = t.tabix_intervals("chr1:99-200") - results = str(results) - print(results) - assert results == fix( - """ - chr1 1 100 feature1 0 + - chr1 100 200 feature2 0 + - chr1 150 500 feature3 0 -""" - ) + for idx_type in ("tbi", "csi"): + try: + a = pybedtools.example_bedtool("a.bed") + t = a.tabix(force=True, use_csi=True if idx_type == "csi" else False) + assert t._tabixed() + results = t.tabix_intervals("chr1:99-200") + results = str(results) + print(results) + assert results == fix( + """ + chr1 1 100 feature1 0 + + chr1 100 200 feature2 0 + + chr1 150 500 feature3 0 -""" + ) - assert str(t.tabix_intervals(a[2])) == fix( - """ - chr1 100 200 feature2 0 + - chr1 150 500 feature3 0 -""" - ) + assert str(t.tabix_intervals(a[2])) == fix( + """ + chr1 100 200 feature2 0 + + chr1 150 500 feature3 0 -""" + ) - finally: - # clean up - fns = [ - pybedtools.example_filename("a.bed.gz"), - pybedtools.example_filename("a.bed.gz.tbi"), - ] - for fn in fns: - if os.path.exists(fn): - os.unlink(fn) + finally: + # clean up + fns = [ + pybedtools.example_filename("a.bed.gz"), + pybedtools.example_filename("a.bed.gz." + idx_type), + ] + for fn in fns: + if os.path.exists(fn): + os.unlink(fn) def test_tabix_intervals(): From e61a315148c4870df84298a5f76f0d482d3a6af9 Mon Sep 17 00:00:00 2001 From: liyao001 Date: Fri, 26 Apr 2024 23:34:08 -0400 Subject: [PATCH 03/16] Extended original test case for `tabix` by testing both tbi and csi indexes (tabix_contigs) --- pybedtools/test/test_1.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pybedtools/test/test_1.py b/pybedtools/test/test_1.py index 54292ee1..20a68393 100644 --- a/pybedtools/test/test_1.py +++ b/pybedtools/test/test_1.py @@ -178,6 +178,12 @@ def test_tabix_intervals(): assert len(a.tabix_intervals("chr1")) == 1 +def test_tabix_contigs_csi(): + a = pybedtools.example_bedtool("a.bed") + a = a.tabix(force=True, use_csi=True) + assert a.tabix_contigs() == ["chr1"] + + # ---------------------------------------------------------------------------- # Streaming and non-file BedTool tests # ---------------------------------------------------------------------------- From 3a5ebc8d66214bfbeb9629b9b27a5b2dd0309217 Mon Sep 17 00:00:00 2001 From: Li Yao Date: Fri, 5 Jul 2024 22:44:15 -0400 Subject: [PATCH 04/16] Update a docstring to trigger github actions --- pybedtools/bedtool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybedtools/bedtool.py b/pybedtools/bedtool.py index 11ebcf72..96ada4b0 100644 --- a/pybedtools/bedtool.py +++ b/pybedtools/bedtool.py @@ -783,7 +783,7 @@ def tabix(self, in_place=True, force=False, is_sorted=False, use_csi=False): so that BedTool.bgzip() doesn't have to do that work. use_csi : bool - If True (default is False), then generate csi instead of tbi index. + If True (default is False), then generate a csi instead of tbi index. This can be useful when working with chromosomes larger than 512 Mbp, such as barley """ # Return quickly if nothing to do From 9cfa49cf1861f23422a3b7433804bc98a398fc55 Mon Sep 17 00:00:00 2001 From: Govinda Kamath Date: Fri, 24 Jul 2026 14:01:59 -0700 Subject: [PATCH 05/16] build: add wheels to pypi --- .github/workflows/main.yml | 63 +++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 33efd207..188ba94a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,6 +3,8 @@ on: push: branches: - master + tags: + - 'v*' pull_request: types: - opened @@ -13,7 +15,7 @@ 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"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -48,6 +50,12 @@ jobs: (cd dist && pip install pybedtools-*.tar.gz && cd $TMPDIR && python -c 'import pybedtools; print(pybedtools.__file__)') conda deactivate + - name: upload sdist + if: ${{ matrix.python-version == '3.12' }} + uses: actions/upload-artifact@v4 + with: + name: sdist + path: dist/pybedtools-*.tar.gz - name: conda env and install locally # Set up conda and install pybedtools into that env @@ -150,3 +158,56 @@ jobs: 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@v4 + + - name: Build wheels + uses: pypa/cibuildwheel@v2.21.3 + 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' && python setup.py cythonize" + + - uses: actions/upload-artifact@v4 + with: + name: wheels-${{ matrix.os }} + path: ./wheelhouse/*.whl + + + publish: + needs: [build-and-test, build-wheels] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + environment: pypi + permissions: + id-token: write + + steps: + - uses: actions/download-artifact@v4 + with: + pattern: wheels-* + merge-multiple: true + path: dist/ + + - uses: actions/download-artifact@v4 + with: + name: sdist + path: dist/ + + - uses: pypa/gh-action-pypi-publish@release/v1 From 0f3f4dcf8371ef923c6713dbf08322974c40223b Mon Sep 17 00:00:00 2001 From: Govinda Kamath Date: Sun, 26 Jul 2026 11:55:42 -0700 Subject: [PATCH 06/16] ci: trigger Actions test From ea79e3223b08d8db5e1035817594825401ed5431 Mon Sep 17 00:00:00 2001 From: Govinda Kamath Date: Sun, 26 Jul 2026 12:02:12 -0700 Subject: [PATCH 07/16] ci: fix setuptools missing in cibuildwheel and liblzma-dev for pysam on 3.14 --- .github/workflows/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 188ba94a..de7e486d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,6 +32,9 @@ jobs: echo "BRANCH=${GITHUB_REF##*/}" >> $GITHUB_ENV echo "WORKDIR=$(pwd)" >> $GITHUB_ENV + - name: install system deps + run: sudo apt-get install -y liblzma-dev + - name: install miniforge run: | wget -O Miniforge3.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh" @@ -182,7 +185,7 @@ jobs: CIBW_ARCHS: ${{ matrix.cibw_archs }} CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-* cp314-*" CIBW_SKIP: "*-win*" - CIBW_BEFORE_BUILD: "pip install 'cython>3.0' && python setup.py cythonize" + CIBW_BEFORE_BUILD: "pip install 'cython>3.0' setuptools && python setup.py cythonize" - uses: actions/upload-artifact@v4 with: From 21cf373a78d302b5331650336b34528be5172f03 Mon Sep 17 00:00:00 2001 From: Govinda Kamath Date: Sun, 26 Jul 2026 12:14:02 -0700 Subject: [PATCH 08/16] ci: add xz to cython-env so pysam can find liblzma via conda pkg-config --- .github/workflows/main.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index de7e486d..4b45ec2f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,9 +32,6 @@ jobs: echo "BRANCH=${GITHUB_REF##*/}" >> $GITHUB_ENV echo "WORKDIR=$(pwd)" >> $GITHUB_ENV - - name: install system deps - run: sudo apt-get install -y liblzma-dev - - name: install miniforge run: | wget -O Miniforge3.sh "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh" @@ -47,7 +44,7 @@ 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__)') From 1d4ea538c21653f82bf65cd21614a64de0618291 Mon Sep 17 00:00:00 2001 From: Ryan Dale <115406+daler@users.noreply.github.com> Date: Fri, 21 Aug 2026 10:11:47 -0400 Subject: [PATCH 09/16] rm publish step --- .github/workflows/main.yml | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4b45ec2f..b65841a0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -188,26 +188,3 @@ jobs: with: name: wheels-${{ matrix.os }} path: ./wheelhouse/*.whl - - - publish: - needs: [build-and-test, build-wheels] - runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/v') - environment: pypi - permissions: - id-token: write - - steps: - - uses: actions/download-artifact@v4 - with: - pattern: wheels-* - merge-multiple: true - path: dist/ - - - uses: actions/download-artifact@v4 - with: - name: sdist - path: dist/ - - - uses: pypa/gh-action-pypi-publish@release/v1 From a97c7e4f2a7b6139cd703613b1cd3af5ed0009f0 Mon Sep 17 00:00:00 2001 From: Ryan Dale <115406+daler@users.noreply.github.com> Date: Fri, 21 Aug 2026 16:55:46 -0400 Subject: [PATCH 10/16] ci: handle fork missing gh-pages --- .github/workflows/main.yml | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b65841a0..70b70b78 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -125,17 +125,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' From 2612996345ce5597b0daeb7082e954537a5a1747 Mon Sep 17 00:00:00 2001 From: Ryan Dale <115406+daler@users.noreply.github.com> Date: Fri, 21 Aug 2026 16:57:19 -0400 Subject: [PATCH 11/16] ci: bump version of various actions --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 70b70b78..3a95e367 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: git setup @@ -52,7 +52,7 @@ jobs: - name: upload sdist if: ${{ matrix.python-version == '3.12' }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: sdist path: dist/pybedtools-*.tar.gz @@ -157,7 +157,7 @@ jobs: - name: docs artifact # Upload built docs as an artifact for inspection, even on PRs - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: docs path: /tmp/docs @@ -186,17 +186,17 @@ jobs: cibw_archs: "arm64 x86_64" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 - name: Build wheels - uses: pypa/cibuildwheel@v2.21.3 + 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@v4 + - uses: actions/upload-artifact@v7 with: name: wheels-${{ matrix.os }} path: ./wheelhouse/*.whl From 1a8d9c6ab7b538184ce75e01eb5caa36996ca2c5 Mon Sep 17 00:00:00 2001 From: Ryan Dale <115406+daler@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:11:31 -0400 Subject: [PATCH 12/16] test: make test_118 more accurate counting fds --- pybedtools/test/test_issues.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/pybedtools/test/test_issues.py b/pybedtools/test/test_issues.py index 810e4100..22a4901a 100644 --- a/pybedtools/test/test_issues.py +++ b/pybedtools/test/test_issues.py @@ -8,6 +8,7 @@ from pathlib import Path import pytest import psutil +import gc from pybedtools import filenames @@ -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(): From d4a333ab45687272da401d78d912335b1dfdb932 Mon Sep 17 00:00:00 2001 From: Ryan Dale <115406+daler@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:00:21 -0400 Subject: [PATCH 13/16] ci: better selection of sdist/docs version --- .github/workflows/main.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a95e367..4de28a84 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,6 +16,10 @@ jobs: strategy: matrix: 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@v7 @@ -51,7 +55,7 @@ jobs: conda deactivate - name: upload sdist - if: ${{ matrix.python-version == '3.12' }} + if: matrix.canonical uses: actions/upload-artifact@v7 with: name: sdist @@ -114,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: | @@ -157,6 +161,7 @@ jobs: - name: docs artifact # Upload built docs as an artifact for inspection, even on PRs + if: matrix.canonical uses: actions/upload-artifact@v7 with: name: docs @@ -165,7 +170,7 @@ jobs: - 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 From 0285930c7c2e2448eef8e8528bb4e5aa891577dd Mon Sep 17 00:00:00 2001 From: Ryan Dale <115406+daler@users.noreply.github.com> Date: Tue, 25 Aug 2026 13:34:46 -0400 Subject: [PATCH 14/16] bump version --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index bf234d24..023bdcae 100644 --- a/setup.py +++ b/setup.py @@ -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): From 621c527abc5d8e5571117a665f8d0055e3b9fe93 Mon Sep 17 00:00:00 2001 From: Ryan Dale <115406+daler@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:50:00 -0400 Subject: [PATCH 15/16] bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 023bdcae..e0e646b3 100644 --- a/setup.py +++ b/setup.py @@ -71,7 +71,7 @@ MAJ = 0 MIN = 12 -REV = '1a' +REV = 1 VERSION = f'{MAJ}.{MIN}.{REV}' From 1a18c2d37f4560f86c30555005355c31799f1848 Mon Sep 17 00:00:00 2001 From: Ryan Dale <115406+daler@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:52:41 -0400 Subject: [PATCH 16/16] add RELEASE.md --- RELEASE.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 00000000..0706ffb3 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,54 @@ +# Releases + +As of v0.12.1, wheels are built as part of the GitHub Actions workflow. Rather +than tie these in to an automated push-to-PyPI process, for now publishing to +PyPI continues as a manual process -- but now with wheels in addition to the +sdist. + +First, merge to master and wait for CI to finish. + +Get the run ID from the merge's GitHub Actions run. Use that, plus the `gh` +command-line tool, to download the artifacts. + +```bash +RUN_ID="" +rm -r staging && mkdir -p staging +rm -r dist && mkdir -p dist + +# Download all wheels and the sdist, store 'em in staging/. +# We'll have subdirectories for each arch/os +gh run download $RUN_ID -p 'wheels-*' -p sdist -D staging + +# Flatten nested wheels & sdist into the dist/ dir +mkdir dist && find staging -type f \( -name '*.whl' -o -name '*.tar.gz' \) -exec mv {} dist/ \; +``` + +Tag the release. + +```bash +TAG="" +git tag -s $TAG && git push origin $TAG +``` + +Check the dist, run a local test install, then upload to PyPI. + +```bash +ls dist/ + +# x-rst warnings OK +twine check dist/* + +# Test local on linux +python -m venv /tmp/t && /tmp/t/bin/pip install dist/pybedtools-$(echo $TAG | sed "s/v//")-cp312-*manylinux*.whl + +# Or mac +python -m venv /tmp/t && /tmp/t/bin/pip install dist/pybedtools-$(echo $TAG | sed "s/v//")-cp312-*macosx*_arm64.whl + +# Test PyPI +twine upload -r testpypi dist/* + +# Prod PyPI +twine upload dist/* +``` + +Bioconda builds should pick it up in an hour or so after pushing to PyPI.