Skip to content
Snippets Groups Projects
Commit 09b60b2f authored by Paul McCarthy's avatar Paul McCarthy :mountain_bicyclist:
Browse files

Merge branch 'mnt/py38' into 'master'

Mnt/py38

See merge request fsl/fslpy!165
parents 5022ae99 eff35718
No related branches found
No related tags found
No related merge requests found
...@@ -157,27 +157,27 @@ variables: ...@@ -157,27 +157,27 @@ variables:
- bash ./.ci/test_template.sh - bash ./.ci/test_template.sh
test:3.5: test:3.6:
stage: test stage: test
image: pauldmccarthy/fsleyes-py35-wxpy4-gtk2 image: pauldmccarthy/fsleyes-py36-wxpy4-gtk3
<<: *test_template <<: *test_template
test:3.6: test:3.7:
stage: test stage: test
image: pauldmccarthy/fsleyes-py36-wxpy4-gtk2 image: pauldmccarthy/fsleyes-py37-wxpy4-gtk3
<<: *test_template <<: *test_template
test:3.7: test:3.8:
stage: test stage: test
image: pauldmccarthy/fsleyes-py37-wxpy4-gtk2 image: pauldmccarthy/fsleyes-py38-wxpy4-gtk3
<<: *test_template <<: *test_template
test:build-pypi-dist: test:build-pypi-dist:
stage: test stage: test
image: pauldmccarthy/fsleyes-py35-wxpy4-gtk2 image: pauldmccarthy/fsleyes-py36-wxpy4-gtk3
<<: *except_releases <<: *except_releases
tags: tags:
...@@ -195,7 +195,7 @@ test:build-pypi-dist: ...@@ -195,7 +195,7 @@ test:build-pypi-dist:
style: style:
stage: style stage: style
image: pauldmccarthy/fsleyes-py35-wxpy4-gtk2 image: pauldmccarthy/fsleyes-py36-wxpy4-gtk3
<<: *test_template <<: *test_template
variables: variables:
TEST_STYLE: "true" TEST_STYLE: "true"
......
...@@ -2,6 +2,18 @@ This document contains the ``fslpy`` release history in reverse chronological ...@@ -2,6 +2,18 @@ This document contains the ``fslpy`` release history in reverse chronological
order. order.
2.6.1 (Thursday 19th September 2019)
------------------------------------
Changed
^^^^^^^
* ``fslpy`` is no longer tested against Python 3.5, and is now tested against
Python 3.6, 3.7, and 3.8.
2.6.0 (Tuesday 10th September 2019) 2.6.0 (Tuesday 10th September 2019)
----------------------------------- -----------------------------------
......
...@@ -77,7 +77,7 @@ def read_line(line: str) -> Tuple[int, PurePath, str]: ...@@ -77,7 +77,7 @@ def read_line(line: str) -> Tuple[int, PurePath, str]:
""" """
Parses line from the tree file Parses line from the tree file
:param line: input line from a \*.tree file :param line: input line from a ``*.tree`` file
:return: Tuple with: :return: Tuple with:
- number of spaces in front of the name - number of spaces in front of the name
...@@ -105,7 +105,7 @@ def read_subtree_line(line: str, directory: str) -> Tuple[int, "filetree.FileTre ...@@ -105,7 +105,7 @@ def read_subtree_line(line: str, directory: str) -> Tuple[int, "filetree.FileTre
""" """
Parses the line defining a sub_tree Parses the line defining a sub_tree
:param line: input line from a \*.tree file :param line: input line from a ``*.tree`` file
:param directory: containing directory :param directory: containing directory
:return: Tuple with :return: Tuple with
......
...@@ -48,9 +48,8 @@ class FileTreeQuery(object): ...@@ -48,9 +48,8 @@ class FileTreeQuery(object):
short name that are present. The :meth:`query` method can be used to short name that are present. The :meth:`query` method can be used to
retrieve files which match a specific template, and variable values. retrieve files which match a specific template, and variable values.
The :meth:`query` method returns a multi-dimensional ``numpy.array`` The :meth:`query` method returns a collection of :class:`Match` objects,
which contains :class:`Match` objects, where each dimension one each of which represents one file which matches the query.
represents variable for the template in question.
Example usage:: Example usage::
......
...@@ -98,7 +98,7 @@ def resolve_optionals(text): ...@@ -98,7 +98,7 @@ def resolve_optionals(text):
else: else:
return '' return ''
res = [resolve_single_optional(text) for text in re.split('(\[.*?\])', text)] res = [resolve_single_optional(text) for text in re.split(r'(\[.*?\])', text)]
return ''.join(res) return ''.join(res)
...@@ -109,7 +109,7 @@ def find_variables(template): ...@@ -109,7 +109,7 @@ def find_variables(template):
:param template: full template :param template: full template
:return: sequence of variables :return: sequence of variables
""" """
return tuple(var.split(':')[0] for var in re.findall("\{(.*?)\}", template)) return tuple(var.split(':')[0] for var in re.findall(r"\{(.*?)\}", template))
def optional_variables(template): def optional_variables(template):
...@@ -121,7 +121,7 @@ def optional_variables(template): ...@@ -121,7 +121,7 @@ def optional_variables(template):
""" """
include = set() include = set()
exclude = set() exclude = set()
for text in re.split('(\[.*?\])', template): for text in re.split(r'(\[.*?\])', template):
if len(text) == 0: if len(text) == 0:
continue continue
variables = find_variables(text) variables = find_variables(text)
...@@ -152,13 +152,13 @@ def extract_variables(template, filename, known_vars=None): ...@@ -152,13 +152,13 @@ def extract_variables(template, filename, known_vars=None):
sub_re = resolve_optionals(fill_known( sub_re = resolve_optionals(fill_known(
template, template,
dict( dict(
**{var: '(\S+)' for k, var in zip(keep, optional) if k}, **{var: r'(\S+)' for k, var in zip(keep, optional) if k},
**{var: '(\S+)' for var in remaining.difference(optional)} **{var: r'(\S+)' for var in remaining.difference(optional)}
) )
)) ))
while '//' in sub_re: while '//' in sub_re:
sub_re = sub_re.replace('//', '/') sub_re = sub_re.replace('//', '/')
sub_re = sub_re.replace('.', '\.') sub_re = sub_re.replace('.', r'\.')
if re.match(sub_re, filename) is None: if re.match(sub_re, filename) is None:
continue continue
......
...@@ -86,7 +86,7 @@ import atexit ...@@ -86,7 +86,7 @@ import atexit
import logging import logging
import functools import functools
import threading import threading
import collections from collections import abc
try: import queue try: import queue
except ImportError: import Queue as queue except ImportError: import Queue as queue
...@@ -610,7 +610,7 @@ def wait(threads, task, *args, **kwargs): ...@@ -610,7 +610,7 @@ def wait(threads, task, *args, **kwargs):
direct = kwargs.pop('wait_direct', False) direct = kwargs.pop('wait_direct', False)
if not isinstance(threads, collections.Sequence): if not isinstance(threads, abc.Sequence):
threads = [threads] threads = [threads]
haveWX = fslplatform.haveGui haveWX = fslplatform.haveGui
......
...@@ -5,21 +5,21 @@ test=pytest ...@@ -5,21 +5,21 @@ test=pytest
universal=1 universal=1
[tool:pytest] [tool:pytest]
# Available test markers: markers =
# - fsltest: Requires FSL fsltest: Requires FSL
# - wxtest: Requires wxPython wxtest: Requires wxPython
# - dicomtest: Requires dcm2niix dicomtest: Requires dcm2niix
# - meshtest: Requires trimesh and rtree meshtest: Requires trimesh and rtree
# - igziptest: Requires indexed_gzip igziptest: Requires indexed_gzip
# - piltest: Requires Pillow piltest: Requires Pillow
# - noroottest: Need to be executed as noroottest: Need to be executed as non-root user (will fail otherwise)
# non-root user (will fail longtest: Takes a long time
# otherwise) unixtest: Only works on *nix systems
# - longtest: Takes a long time
#
testpaths = tests testpaths = tests
addopts = -v --niters=50 --cov=fsl -m "not longtest" addopts = -v --niters=50 --cov=fsl -m "not longtest"
[flake8] [flake8]
ignore = E127,E201,E203,E221,E222,E241,E271,E272,E301,E302,E303,E701,W504 ignore = E127,E201,E203,E221,E222,E241,E271,E272,E301,E302,E303,E701,W504
\ No newline at end of file
...@@ -9,13 +9,13 @@ import pytest ...@@ -9,13 +9,13 @@ import pytest
import scipy.ndimage as ndimage import scipy.ndimage as ndimage
import fsl.data.image as fslimage import fsl.data.image as fslimage
import fsl.utils.transform as transform import fsl.transform.affine as affine
import fsl.utils.image.resample as resample import fsl.utils.image.resample as resample
from . import make_random_image from . import make_random_image
def random_affine(): def random_affine():
return transform.compose( return affine.compose(
0.25 + 4.75 * np.random.random(3), 0.25 + 4.75 * np.random.random(3),
-50 + 100 * np.random.random(3), -50 + 100 * np.random.random(3),
-np.pi + 2 * np.pi * np.random.random(3)) -np.pi + 2 * np.pi * np.random.random(3))
...@@ -61,9 +61,9 @@ def test_resample(seed): ...@@ -61,9 +61,9 @@ def test_resample(seed):
resx, resy, resz = restestcoords.T resx, resy, resz = restestcoords.T
resvals = resampled[resx, resy, resz] resvals = resampled[resx, resy, resz]
res2orig = transform.concat(img.worldToVoxMat, xf) res2orig = affine.concat(img.worldToVoxMat, xf)
origtestcoords = transform.transform(restestcoords, res2orig) origtestcoords = affine.transform(restestcoords, res2orig)
# remove any coordinates which are out of # remove any coordinates which are out of
# bounds in the original image space, or # bounds in the original image space, or
...@@ -130,8 +130,8 @@ def test_resample_origin(seed): ...@@ -130,8 +130,8 @@ def test_resample_origin(seed):
shape = np.random.randint(5, 50, 3) shape = np.random.randint(5, 50, 3)
res = resample.resample(img, shape, origin='corner') res = resample.resample(img, shape, origin='corner')
res = fslimage.Image(res[0], xform=res[1]) res = fslimage.Image(res[0], xform=res[1])
imgb = transform.axisBounds(img.shape, img.voxToWorldMat) imgb = affine.axisBounds(img.shape, img.voxToWorldMat)
resb = transform.axisBounds(res.shape, res.voxToWorldMat) resb = affine.axisBounds(res.shape, res.voxToWorldMat)
assert np.all(np.isclose(imgb, resb, rtol=1e-5, atol=1e-5)) assert np.all(np.isclose(imgb, resb, rtol=1e-5, atol=1e-5))
# with origin='centre' image # with origin='centre' image
...@@ -142,8 +142,8 @@ def test_resample_origin(seed): ...@@ -142,8 +142,8 @@ def test_resample_origin(seed):
res = resample.resample(img, shape, origin='centre') res = resample.resample(img, shape, origin='centre')
res = fslimage.Image(res[0], xform=res[1]) res = fslimage.Image(res[0], xform=res[1])
off = (np.array(img.shape) / np.array(res.shape) - 1) / 2 off = (np.array(img.shape) / np.array(res.shape) - 1) / 2
imgb = np.array(transform.axisBounds(img.shape, img.voxToWorldMat)) imgb = np.array(affine.axisBounds(img.shape, img.voxToWorldMat))
resb = np.array(transform.axisBounds(res.shape, res.voxToWorldMat)) resb = np.array(affine.axisBounds(res.shape, res.voxToWorldMat))
assert np.all(np.isclose(imgb, resb + off, rtol=1e-5, atol=1e-5)) assert np.all(np.isclose(imgb, resb + off, rtol=1e-5, atol=1e-5))
# with origin='corner', using # with origin='corner', using
...@@ -165,7 +165,7 @@ def test_resample_origin(seed): ...@@ -165,7 +165,7 @@ def test_resample_origin(seed):
def test_resampleToPixdims(): def test_resampleToPixdims():
img = fslimage.Image(make_random_image(dims=(10, 10, 10))) img = fslimage.Image(make_random_image(dims=(10, 10, 10)))
imglo, imghi = transform.axisBounds(img.shape, img.voxToWorldMat) imglo, imghi = affine.axisBounds(img.shape, img.voxToWorldMat)
oldpix = np.array(img.pixdim, dtype=np.float) oldpix = np.array(img.pixdim, dtype=np.float)
oldshape = np.array(img.shape, dtype=np.float) oldshape = np.array(img.shape, dtype=np.float)
...@@ -177,7 +177,7 @@ def test_resampleToPixdims(): ...@@ -177,7 +177,7 @@ def test_resampleToPixdims():
res = resample.resampleToPixdims(img, newpix, origin=origin) res = resample.resampleToPixdims(img, newpix, origin=origin)
res = fslimage.Image(res[0], xform=res[1]) res = fslimage.Image(res[0], xform=res[1])
reslo, reshi = transform.axisBounds(res.shape, res.voxToWorldMat) reslo, reshi = affine.axisBounds(res.shape, res.voxToWorldMat)
resfov = reshi - reslo resfov = reshi - reslo
expfov = newpix * res.shape expfov = newpix * res.shape
...@@ -219,7 +219,7 @@ def test_resampleToReference2(): ...@@ -219,7 +219,7 @@ def test_resampleToReference2():
img[1, 1, 1] = 1 img[1, 1, 1] = 1
img = fslimage.Image(img) img = fslimage.Image(img)
refv2w = transform.scaleOffsetXform([1, 1, 1], [-1, -1, -1]) refv2w = affine.scaleOffsetXform([1, 1, 1], [-1, -1, -1])
ref = np.zeros((5, 5, 5), dtype=np.float) ref = np.zeros((5, 5, 5), dtype=np.float)
ref = fslimage.Image(ref, xform=refv2w) ref = fslimage.Image(ref, xform=refv2w)
res = resample.resampleToReference(img, ref, order=0) res = resample.resampleToReference(img, ref, order=0)
...@@ -235,7 +235,7 @@ def test_resampleToReference3(): ...@@ -235,7 +235,7 @@ def test_resampleToReference3():
# Test resampling image to ref # Test resampling image to ref
# with mismatched dimensions # with mismatched dimensions
imgdata = np.random.randint(0, 65536, (5, 5, 5)) imgdata = np.random.randint(0, 65536, (5, 5, 5))
img = fslimage.Image(imgdata, xform=transform.scaleOffsetXform( img = fslimage.Image(imgdata, xform=affine.scaleOffsetXform(
(2, 2, 2), (0.5, 0.5, 0.5))) (2, 2, 2), (0.5, 0.5, 0.5)))
# reference/expected data when # reference/expected data when
...@@ -270,7 +270,7 @@ def test_resampleToReference4(): ...@@ -270,7 +270,7 @@ def test_resampleToReference4():
# the image and ref are out of # the image and ref are out of
# alignment, but this affine # alignment, but this affine
# will bring them into alignment # will bring them into alignment
img2ref = transform.scaleOffsetXform([2, 2, 2], [10, 10, 10]) img2ref = affine.scaleOffsetXform([2, 2, 2], [10, 10, 10])
imgdata = np.random.randint(0, 65536, (5, 5, 5)) imgdata = np.random.randint(0, 65536, (5, 5, 5))
refdata = np.zeros((5, 5, 5)) refdata = np.zeros((5, 5, 5))
......
...@@ -286,7 +286,7 @@ def _eval_coord_voxel_query( ...@@ -286,7 +286,7 @@ def _eval_coord_voxel_query(
else: else:
exp = [q_type, squery] exp = [q_type, squery]
_stdout = re.sub('\s+', ' ', stdout).strip() _stdout = re.sub(r'\s+', ' ', stdout).strip()
assert _stdout == ' '.join(exp) assert _stdout == ' '.join(exp)
if isinstance(a_img, fslatlases.LabelAtlas): if isinstance(a_img, fslatlases.LabelAtlas):
...@@ -388,7 +388,7 @@ def _eval_mask_query( ...@@ -388,7 +388,7 @@ def _eval_mask_query(
if expprop > 0: if expprop > 0:
exp.append('{} {:0.4f}'.format(explabel, expprop)) exp.append('{} {:0.4f}'.format(explabel, expprop))
_stdout = re.sub('\s+', ' ', stdout).strip() _stdout = re.sub(r'\s+', ' ', stdout).strip()
assert _stdout == ' '.join(exp) assert _stdout == ' '.join(exp)
if isinstance(aimg, fslatlases.LabelAtlas): if isinstance(aimg, fslatlases.LabelAtlas):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment