Skip to content

Commit 9c568dc

Browse files
authored
Merge pull request #1247 from effigies/ci/py312
CI: Begin testing on Python 3.12
2 parents 5f37398 + a42321f commit 9c568dc

File tree

6 files changed

+52
-35
lines changed

6 files changed

+52
-35
lines changed

.github/workflows/pre-release.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
strategy:
3434
matrix:
3535
os: ['ubuntu-latest', 'windows-latest', 'macos-latest']
36-
python-version: ["3.9", "3.10", "3.11"]
36+
python-version: ["3.9", "3.10", "3.11", "3.12"]
3737
architecture: ['x64', 'x86']
3838
install: ['pip']
3939
check: ['test']
@@ -54,6 +54,8 @@ jobs:
5454
architecture: x86
5555
- os: macos-latest
5656
architecture: x86
57+
- python-version: '3.12'
58+
architecture: x86
5759

5860
env:
5961
DEPENDS: ${{ matrix.depends }}
@@ -72,6 +74,7 @@ jobs:
7274
with:
7375
python-version: ${{ matrix.python-version }}
7476
architecture: ${{ matrix.architecture }}
77+
allow-prereleases: true
7578
- name: Display Python version
7679
run: python -c "import sys; print(sys.version)"
7780
- name: Create virtual environment

nibabel/openers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ def __init__(
7878
mtime=mtime,
7979
)
8080

81+
def seek(self, pos: int, whence: int = 0, /) -> int:
82+
# Work around bug (gh-180111) in Python 3.12rc1, where seeking without
83+
# flushing can cause write of excess null bytes
84+
self.flush()
85+
return super().seek(pos, whence)
86+
8187

8288
def _gzip_open(
8389
filename: str,

nibabel/streamlines/tests/test_streamlines.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def setup():
8484
)
8585

8686

87-
def test_is_supported_detect_format():
87+
def test_is_supported_detect_format(tmp_path):
8888
# Test is_supported and detect_format functions
8989
# Empty file/string
9090
f = BytesIO()
@@ -103,15 +103,17 @@ def test_is_supported_detect_format():
103103

104104
# Wrong extension but right magic number
105105
for tfile_cls in FORMATS.values():
106-
with tempfile.TemporaryFile(mode='w+b', suffix='.txt') as f:
106+
fpath = tmp_path / 'test.txt'
107+
with open(fpath, 'w+b') as f:
107108
f.write(asbytes(tfile_cls.MAGIC_NUMBER))
108109
f.seek(0, os.SEEK_SET)
109110
assert nib.streamlines.is_supported(f)
110111
assert nib.streamlines.detect_format(f) is tfile_cls
111112

112113
# Good extension but wrong magic number
113114
for ext, tfile_cls in FORMATS.items():
114-
with tempfile.TemporaryFile(mode='w+b', suffix=ext) as f:
115+
fpath = tmp_path / f'test{ext}'
116+
with open(fpath, 'w+b') as f:
115117
f.write(b'pass')
116118
f.seek(0, os.SEEK_SET)
117119
assert not nib.streamlines.is_supported(f)

nibabel/tests/test_image_api.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import io
2727
import pathlib
28+
import sys
2829
import warnings
2930
from functools import partial
3031
from itertools import product
@@ -579,6 +580,10 @@ def validate_from_url(self, imaker, params):
579580
del img
580581
del rt_img
581582

583+
@pytest.mark.xfail(
584+
sys.version_info >= (3, 12),
585+
reason='Response type for file: urls is not a stream in Python 3.12',
586+
)
582587
def validate_from_file_url(self, imaker, params):
583588
tmp_path = self.tmp_path
584589

nibabel/tests/test_openers.py

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -127,35 +127,36 @@ def patch_indexed_gzip(state):
127127
yield
128128

129129

130-
def test_Opener_gzip_type():
131-
# Test that BufferedGzipFile or IndexedGzipFile are used as appropriate
132-
133-
data = 'this is some test data'
134-
fname = 'test.gz'
135-
136-
with InTemporaryDirectory():
137-
138-
# make some test data
139-
with GzipFile(fname, mode='wb') as f:
140-
f.write(data.encode())
141-
142-
# Each test is specified by a tuple containing:
143-
# (indexed_gzip present, Opener kwargs, expected file type)
144-
tests = [
145-
(False, {'mode': 'rb', 'keep_open': True}, GzipFile),
146-
(False, {'mode': 'rb', 'keep_open': False}, GzipFile),
147-
(False, {'mode': 'wb', 'keep_open': True}, GzipFile),
148-
(False, {'mode': 'wb', 'keep_open': False}, GzipFile),
149-
(True, {'mode': 'rb', 'keep_open': True}, MockIndexedGzipFile),
150-
(True, {'mode': 'rb', 'keep_open': False}, MockIndexedGzipFile),
151-
(True, {'mode': 'wb', 'keep_open': True}, GzipFile),
152-
(True, {'mode': 'wb', 'keep_open': False}, GzipFile),
153-
]
154-
155-
for test in tests:
156-
igzip_present, kwargs, expected = test
157-
with patch_indexed_gzip(igzip_present):
158-
assert isinstance(Opener(fname, **kwargs).fobj, expected)
130+
def test_Opener_gzip_type(tmp_path):
131+
# Test that GzipFile or IndexedGzipFile are used as appropriate
132+
133+
data = b'this is some test data'
134+
fname = tmp_path / 'test.gz'
135+
136+
# make some test data
137+
with GzipFile(fname, mode='wb') as f:
138+
f.write(data)
139+
140+
# Each test is specified by a tuple containing:
141+
# (indexed_gzip present, Opener kwargs, expected file type)
142+
tests = [
143+
(False, {'mode': 'rb', 'keep_open': True}, GzipFile),
144+
(False, {'mode': 'rb', 'keep_open': False}, GzipFile),
145+
(False, {'mode': 'wb', 'keep_open': True}, GzipFile),
146+
(False, {'mode': 'wb', 'keep_open': False}, GzipFile),
147+
(True, {'mode': 'rb', 'keep_open': True}, MockIndexedGzipFile),
148+
(True, {'mode': 'rb', 'keep_open': False}, MockIndexedGzipFile),
149+
(True, {'mode': 'wb', 'keep_open': True}, GzipFile),
150+
(True, {'mode': 'wb', 'keep_open': False}, GzipFile),
151+
]
152+
153+
for test in tests:
154+
igzip_present, kwargs, expected = test
155+
with patch_indexed_gzip(igzip_present):
156+
opener = Opener(fname, **kwargs)
157+
assert isinstance(opener.fobj, expected)
158+
# Explicit close to appease Windows
159+
del opener
159160

160161

161162
class TestImageOpener(unittest.TestCase):

tools/ci/install_dependencies.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ if [ -n "$EXTRA_PIP_FLAGS" ]; then
1919
fi
2020

2121
if [ -n "$DEPENDS" ]; then
22-
pip install ${EXTRA_PIP_FLAGS} --prefer-binary ${!DEPENDS}
22+
pip install ${EXTRA_PIP_FLAGS} --only-binary :all: ${!DEPENDS}
2323
if [ -n "$OPTIONAL_DEPENDS" ]; then
2424
for DEP in ${!OPTIONAL_DEPENDS}; do
25-
pip install ${EXTRA_PIP_FLAGS} --prefer-binary $DEP || true
25+
pip install ${EXTRA_PIP_FLAGS} --only-binary :all: $DEP || true
2626
done
2727
fi
2828
fi

0 commit comments

Comments
 (0)