From 74bb9a7b594455970d92703fed4da61ec5ea1f97 Mon Sep 17 00:00:00 2001 From: Aditya Vaidya Date: Sat, 14 Mar 2026 01:54:31 -0700 Subject: [PATCH 1/2] Remove some old Python 2/3 syntax --- cortex/__init__.py | 7 +------ cortex/align.py | 1 - cortex/appdirs.py | 2 +- cortex/brainctm.py | 10 +++++----- cortex/database.py | 19 +++++++++---------- cortex/dataset/braindata.py | 31 ++++++++++++++----------------- cortex/dataset/dataset.py | 2 +- cortex/dataset/view2D.py | 6 +++--- cortex/dataset/viewRGB.py | 12 ++++++------ cortex/dataset/views.py | 18 +++++++++--------- cortex/freesurfer.py | 4 +--- cortex/mapper/__init__.py | 2 +- cortex/mapper/mapper.py | 2 +- cortex/mayavi_aligner.py | 14 +++++++------- cortex/quickflat/composite.py | 4 ++-- cortex/quickflat/utils.py | 8 ++++---- cortex/rois.py | 4 ++-- cortex/segment.py | 1 - cortex/svgoverlay.py | 9 ++++----- cortex/utils.py | 4 ++-- cortex/xfm.py | 2 +- 21 files changed, 74 insertions(+), 88 deletions(-) diff --git a/cortex/__init__.py b/cortex/__init__.py index 0c0bc11cd..8fb7c7391 100644 --- a/cortex/__init__.py +++ b/cortex/__init__.py @@ -30,7 +30,7 @@ pass # Create deprecated interface for database -class dep(object): +class dep: def __getattr__(self, name): warnings.warn("cortex.surfs is deprecated, use cortex.db instead", Warning) return getattr(db, name) @@ -41,8 +41,3 @@ def __dir__(self): surfs = dep() import sys -if sys.version_info < (3,): - stdout = sys.stdout - reload(sys) - sys.setdefaultencoding('utf8') - sys.stdout = stdout diff --git a/cortex/align.py b/cortex/align.py index cc1d9913e..7a236db0c 100644 --- a/cortex/align.py +++ b/cortex/align.py @@ -5,7 +5,6 @@ import subprocess as sp import tempfile import warnings -from builtins import input import numpy as np diff --git a/cortex/appdirs.py b/cortex/appdirs.py index efc7f3705..017c6ec60 100644 --- a/cortex/appdirs.py +++ b/cortex/appdirs.py @@ -214,7 +214,7 @@ def user_log_dir(appname, appauthor=None, version=None, opinion=True): return path -class AppDirs(object): +class AppDirs: """Convenience wrapper for getting application dirs.""" def __init__(self, appname, appauthor, version=None, roaming=False): self.appname = appname diff --git a/cortex/brainctm.py b/cortex/brainctm.py index b085598c9..d2fa1cbb1 100644 --- a/cortex/brainctm.py +++ b/cortex/brainctm.py @@ -25,7 +25,7 @@ from . import polyutils from .openctm import CTMfile -class BrainCTM(object): +class BrainCTM: def __init__(self, subject, decimate=False): self.subject = subject self.types = [] @@ -196,7 +196,7 @@ def save(self, path, method='mg2', external_svg=None, fp.write(svg.toxml()) return ptmap -class Hemi(object): +class Hemi: def __init__(self, pts, polys, norms=None): self.tf = tempfile.NamedTemporaryFile() self.tf.name = bytes(self.tf.name, 'ascii') @@ -258,16 +258,16 @@ def __init__(self, pts, polys, fpolys, pia=None): idxmap[mask] = np.arange(mask.sum()).astype(np.uint32) #norms = polyutils.Surface(pts, polys).normals[mask] basepts = pts[mask] if pia is None else pia[mask] - super(DecimatedHemi, self).__init__(basepts, idxmap[allpolys]) + super().__init__(basepts, idxmap[allpolys]) self.aux[idxmap[mwidx], 0] = 1 self.mask = mask self.idxmap = idxmap def setFlat(self, pts): - super(DecimatedHemi, self).setFlat(pts[self.mask]) + super().setFlat(pts[self.mask]) def addSurf(self, pts, **kwargs): - super(DecimatedHemi, self).addSurf(pts[self.mask], **kwargs) + super().addSurf(pts[self.mask], **kwargs) def make_pack(outfile, subj, types=("inflated",), method='raw', level=0, decimate=False, disp_layers=['rois'], diff --git a/cortex/database.py b/cortex/database.py index c99262b1b..336471b10 100644 --- a/cortex/database.py +++ b/cortex/database.py @@ -10,7 +10,6 @@ import shutil import tempfile import warnings -from builtins import input from hashlib import sha1 import numpy as np @@ -33,7 +32,7 @@ def memofn(self, *args, **kwargs): return memofn -class SubjectDB(object): +class SubjectDB: def __init__(self, subj, filestore=default_filestore): self.subject = subj self._warning = None @@ -61,7 +60,7 @@ def surfaces(self): self._surfaces = SurfaceDB(self.subject, filestore=self.filestore) return self._surfaces -class SurfaceDB(object): +class SurfaceDB: def __init__(self, subj, filestore=default_filestore): self.subject = subj self.types = {} @@ -80,7 +79,7 @@ def __getattr__(self, attr): return self.types[attr] raise AttributeError(attr) -class Surf(object): +class Surf: def __init__(self, subject, surftype, filestore=default_filestore): self.subject, self.surftype = subject, surftype self.db = Database(filestore) @@ -93,7 +92,7 @@ def show(self, hemisphere="both"): pts, polys = self.db.get_surf(self.subject, self.surftype, hemisphere, merge=True, nudge=True) return mlab.triangular_mesh(pts[:,0], pts[:,1], pts[:,2], polys) -class XfmDB(object): +class XfmDB: def __init__(self, subj, filestore=default_filestore): self.subject = subj self.filestore = filestore @@ -108,7 +107,7 @@ def __repr__(self): xfms = "\n".join(sorted(self.xfms)) return f"Available transforms for {self.subject}:\n{xfms}" -class XfmSet(object): +class XfmSet: def __init__(self, subj, name, filestore=default_filestore): self.subject = subj self.name = name @@ -126,13 +125,13 @@ def __getattr__(self, attr): def __repr__(self): return "Types: {types}".format(types=", ".join(self._jsdat.keys())) -class MaskSet(object): +class MaskSet: def __init__(self, subj, name, filestore=default_filestore): self.subject = subj self.xfmname = name maskform = Database(filestore).get_paths(subj)['masks'] maskpath = maskform.format(xfmname=name, type='*') - self._masks = dict((os.path.split(path)[1][5:-7], path) for path in glob.glob(maskpath)) + self._masks = {os.path.split(path)[1][5:-7]: path for path in glob.glob(maskpath)} def __getitem__(self, item): import nibabel @@ -141,7 +140,7 @@ def __getitem__(self, item): def __repr__(self): return "Masks: [{types}]".format(types=', '.join(self._masks.keys())) -class Database(object): +class Database: """ Database() @@ -180,7 +179,7 @@ def subjects(self): subjs = os.listdir(os.path.join(self.filestore)) subjs = [s for s in subjs if os.path.isdir(os.path.join(self.filestore, s))] subjs = sorted(subjs) - self._subjects = dict([(sname, SubjectDB(sname, filestore=self.filestore)) for sname in subjs]) + self._subjects = {sname: SubjectDB(sname, filestore=self.filestore) for sname in subjs} return self._subjects def reload_subjects(self): diff --git a/cortex/dataset/braindata.py b/cortex/dataset/braindata.py index 817c024bb..27a92661d 100644 --- a/cortex/dataset/braindata.py +++ b/cortex/dataset/braindata.py @@ -15,7 +15,7 @@ from ..database import db -class BrainData(object): +class BrainData: """ Abstract base class for brain data. @@ -38,7 +38,7 @@ def __init__(self, data: Union[npt.NDArray, str], subject: str, **kwargs): except NameError: subject = subject if isinstance(subject, str) else subject.decode('utf-8') self.subject = subject - super(BrainData, self).__init__(**kwargs) + super().__init__(**kwargs) @property def data(self): @@ -86,7 +86,7 @@ def _write_hdf(self, h5, name=None): def to_json(self, simple=False): """Creates JSON description of this brain data. """ - sdict = super(BrainData, self).to_json(simple=simple) + sdict = super().to_json(simple=simple) if simple: sdict.update(dict(name=self.name, subject=self.subject, @@ -144,11 +144,8 @@ class VolumeData(BrainData): def __init__(self, data: npt.NDArray, subject: str, xfmname: str, mask: Optional[npt.NDArray]=None, **kwargs): if self.__class__ == VolumeData: raise TypeError('Cannot directly instantiate VolumeData objects') - super(VolumeData, self).__init__(data, subject, **kwargs) - try: - basestring - except NameError: - xfmname = xfmname if isinstance(xfmname, str) else xfmname.decode('utf-8') + super().__init__(data, subject, **kwargs) + xfmname = xfmname if isinstance(xfmname, str) else xfmname.decode('utf-8') self.xfmname = xfmname self._check_size(mask) @@ -158,13 +155,13 @@ def to_json(self, simple: bool=False): """Creates JSON description of this brain data. """ if simple: - sdict = super(VolumeData, self).to_json(simple=simple) + sdict = super().to_json(simple=simple) sdict["shape"] = self.shape return sdict xfm = db.get_xfm(self.subject, self.xfmname, 'coord').xfm sdict = dict(xfm=[list(np.array(xfm).ravel())], data=[self.name]) - sdict.update(super(VolumeData, self).to_json()) + sdict.update(super().to_json()) return sdict @classmethod @@ -288,7 +285,7 @@ def __repr__(self): return "<%s data for (%s, %s)>"%(maskstr, self.subject, self.xfmname) def copy(self, data): - return super(VolumeData, self).copy(data, self.subject, self.xfmname, mask=self._mask) + return super().copy(data, self.subject, self.xfmname, mask=self._mask) @property def volume(self): @@ -321,8 +318,8 @@ def save(self, filename, name=None): elif isinstance(filename, h5py.Group): self._write_hdf(filename, name=name) - def _write_hdf(self, h5, name=None): - node = super(VolumeData, self)._write_hdf(h5, name=name) + def _write_hdf(self, h5: Union[h5py.File, h5py.Group], name: Optional[str]=None) -> h5py.Dataset: + node = super()._write_hdf(h5, name=name) #write the mask into the file, as necessary if self._mask is not None: @@ -367,7 +364,7 @@ class VertexData(BrainData): def __init__(self, data: npt.NDArray, subject: str, **kwargs): if self.__class__ == VertexData: raise TypeError('Cannot directly instantiate VertexData objects') - super(VertexData, self).__init__(data, subject, **kwargs) + super().__init__(data, subject, **kwargs) try: left, right = db.get_surf(self.subject, "wm") except IOError: @@ -469,7 +466,7 @@ def copy(self, data: npt.NDArray) -> Self: it doesn't require reloading the surfaces from the database to check numbers of vertices, etc. """ - return super(VertexData, self).copy(data, self.subject) + return super().copy(data, self.subject) def volume(self, xfmname, projection='nearest', **kwargs): """ @@ -518,11 +515,11 @@ def __getitem__(self, idx): def to_json(self, simple: bool = False): if simple: sdict = dict(split=self.llen, frames=self.vertices.shape[0]) - sdict.update(super(VertexData, self).to_json(simple=simple)) + sdict.update(super().to_json(simple=simple)) return sdict sdict = dict(data=[self.name]) - sdict.update(super(VertexData, self).to_json()) + sdict.update(super().to_json()) return sdict @property diff --git a/cortex/dataset/dataset.py b/cortex/dataset/dataset.py index bca3808a3..29a14d8b3 100644 --- a/cortex/dataset/dataset.py +++ b/cortex/dataset/dataset.py @@ -10,7 +10,7 @@ from .views import normalize as _vnorm from .views import Dataview, Vertex, Volume, _from_hdf_data -class Dataset(object): +class Dataset: """ Wrapper for multiple data objects. This often does not need to be used explicitly--for example, if a dictionary of data objects is passed to diff --git a/cortex/dataset/view2D.py b/cortex/dataset/view2D.py index 6a41792ac..922810af3 100644 --- a/cortex/dataset/view2D.py +++ b/cortex/dataset/view2D.py @@ -171,14 +171,14 @@ def __init__(self, dim1: Union[npt.NDArray, Volume], dim2: Union[npt.NDArray, Vo vmax = self.dim1.vmax if vmax is None else vmax vmax2 = self.dim2.vmax if vmax2 is None else vmax2 - super(Volume2D, self).__init__(description=description, cmap=cmap, vmin=vmin, + super().__init__(description=description, cmap=cmap, vmin=vmin, vmax=vmax, vmin2=vmin2, vmax2=vmax2, **kwargs) def __repr__(self): return "<2D volumetric data for (%s, %s)>"%(self.dim1.subject, self.dim1.xfmname) def _write_hdf(self, h5, name="data"): - viewnode = super(Volume2D, self)._write_hdf(h5, name) + viewnode = super()._write_hdf(h5, name) viewnode[7] = json.dumps([[self.dim1.xfmname, self.dim2.xfmname]]) return viewnode @@ -267,7 +267,7 @@ def __init__(self, dim1: Union[npt.NDArray, Vertex], dim2: Union[npt.NDArray, Ve vmax = self.dim1.vmax if vmax is None else vmax vmax2 = self.dim2.vmax if vmax2 is None else vmax2 - super(Vertex2D, self).__init__(description=description, cmap=cmap, + super().__init__(description=description, cmap=cmap, vmin=vmin, vmax=vmax, vmin2=vmin2, vmax2=vmax2, **kwargs) diff --git a/cortex/dataset/viewRGB.py b/cortex/dataset/viewRGB.py index edc068f67..0c1309f9d 100644 --- a/cortex/dataset/viewRGB.py +++ b/cortex/dataset/viewRGB.py @@ -143,7 +143,7 @@ def _write_hdf(self, h5, name="data", xfmname=None): return viewnode def to_json(self, simple=False): - sdict = super(DataviewRGB, self).to_json(simple=simple) + sdict = super().to_json(simple=simple) if simple: sdict["name"] = self.name @@ -558,7 +558,7 @@ def __init__( else: raise ValueError("Cannot handle different transforms per volume") - super(VolumeRGB, self).__init__( + super().__init__( subject, alpha, description=description, state=state, priority=priority ) @@ -591,7 +591,7 @@ def alpha(self, alpha: Optional[Union[npt.NDArray, Volume]]): self._alpha = alpha def to_json(self, simple=False): - sdict = super(VolumeRGB, self).to_json(simple=simple) + sdict = super().to_json(simple=simple) if simple: sdict["shape"] = self.red.shape else: @@ -647,7 +647,7 @@ def name(self): return "__%s" % _hash(self.volume)[:16] def _write_hdf(self, h5, name="data"): - return super(VolumeRGB, self)._write_hdf(h5, name=name, xfmname=[self.xfmname]) + return super()._write_hdf(h5, name=name, xfmname=[self.xfmname]) @property def raw(self): @@ -834,7 +834,7 @@ def __init__( self.blue = Vertex(b, subject) self.alpha = alpha - super(VertexRGB, self).__init__( + super().__init__( subject, alpha, description=description, state=state, priority=priority ) @@ -894,7 +894,7 @@ def vertices(self): return np.array(verts).transpose([1, 2, 0]) def to_json(self, simple=False): - sdict = super(VertexRGB, self).to_json(simple=simple) + sdict = super().to_json(simple=simple) if simple: sdict.update(dict(split=self.red.llen, frames=self.vertices.shape[0])) diff --git a/cortex/dataset/views.py b/cortex/dataset/views.py index ddc9a815f..a42e2e5f9 100644 --- a/cortex/dataset/views.py +++ b/cortex/dataset/views.py @@ -154,7 +154,7 @@ def _from_hdf_view( raise ValueError("Invalid Dataview specification") -class Dataview(object): +class Dataview: def __init__( self, cmap: Optional[str] = None, @@ -303,7 +303,7 @@ def get_cmapdict(self): # unknown colormap, test whether it's in pycortex colormaps cmapdir = options.config.get("webgl", "colormaps") colormaps = glob.glob(os.path.join(cmapdir, "*.png")) - colormaps = dict(((os.path.split(c)[1][:-4], c) for c in colormaps)) + colormaps = {os.path.split(c)[1][:-4]: c for c in colormaps} if self.cmap not in colormaps: raise ValueError("Unknown color map %s" % self.cmap) I = plt.imread(colormaps[self.cmap]) @@ -398,7 +398,7 @@ def __init__( description: str = "", **kwargs, ): - super(Volume, self).__init__( + super().__init__( data, subject, xfmname, @@ -431,8 +431,8 @@ def _write_hdf(self, h5, name="data"): return viewnode @property - def raw(self): - (r, g, b, a), nan_mask = super(Volume, self).raw + def raw(self) -> VolumeRGB: + (r, g, b, a), nan_mask = super().raw result = VolumeRGB( r, g, @@ -488,7 +488,7 @@ def __init__( description: str = "", **kwargs, ): - super(Vertex, self).__init__( + super().__init__( data, subject, cmap=cmap, @@ -515,8 +515,8 @@ def _write_hdf(self, h5, name="data"): return viewnode @property - def raw(self): - (r, g, b, a), nan_mask = super(Vertex, self).raw + def raw(self) -> VertexRGB: + (r, g, b, a), nan_mask = super().raw result = VertexRGB( r, g, @@ -537,7 +537,7 @@ def map( hemi: Literal["lh", "rh", "both"] = "both", fs_subj: Optional[str] = None, **kwargs, - ) -> "Vertex": + ) -> Vertex: """Map this data from this surface to another surface Calls `cortex.freesurfer.vertex_to_vertex()` with this diff --git a/cortex/freesurfer.py b/cortex/freesurfer.py index a76a1700b..bcf797bda 100644 --- a/cortex/freesurfer.py +++ b/cortex/freesurfer.py @@ -1,6 +1,5 @@ """Contains functions for interfacing with freesurfer """ -from __future__ import print_function import copy import os @@ -10,7 +9,6 @@ import subprocess as sp import tempfile import warnings -from builtins import input from tempfile import NamedTemporaryFile import nibabel @@ -1012,7 +1010,7 @@ def write_decimated(path, pts, polys): fp.write(data.tobytes()) -class SpringLayout(object): +class SpringLayout: """ """ def __init__(self, pts, polys, dpts=None, pins=None, stepsize=1, neighborhood=0): diff --git a/cortex/mapper/__init__.py b/cortex/mapper/__init__.py index e1de25f2a..6c67590a4 100644 --- a/cortex/mapper/__init__.py +++ b/cortex/mapper/__init__.py @@ -28,7 +28,7 @@ def get_mapper(subject, xfmname, type='nearest', recache=False, **kwargs): if len(kwds) > 0: ptype += '_'+kwds - fname = "{xfmname}_{projection}.npz".format(xfmname=xfmname, projection=ptype) + fname = f"{xfmname}_{ptype}.npz" xfmfile = db.get_paths(subject)['xfmdir'].format(xfmname=xfmname) cachefile = os.path.join(db.get_cache(subject), fname) diff --git a/cortex/mapper/mapper.py b/cortex/mapper/mapper.py index 6312872f5..17d098080 100644 --- a/cortex/mapper/mapper.py +++ b/cortex/mapper/mapper.py @@ -6,7 +6,7 @@ import warnings warnings.simplefilter('ignore', sparse.SparseEfficiencyWarning) -class Mapper(object): +class Mapper: '''Maps data from epi volume onto surface using various projections''' def __init__(self, left, right, shape, subject, xfmname): self.idxmap = None diff --git a/cortex/mayavi_aligner.py b/cortex/mayavi_aligner.py index 267dd0b0a..5be332044 100644 --- a/cortex/mayavi_aligner.py +++ b/cortex/mayavi_aligner.py @@ -47,7 +47,7 @@ class RotationWidget(HasTraits): def __init__(self, figure, callback, **traits): self._t = np.linspace(0, 2*np.pi, 32) - super(RotationWidget, self).__init__(**traits) + super().__init__(**traits) self.callback = callback self.figure = figure @@ -150,7 +150,7 @@ def OnKeyDown(self, evt): elif key == "\x1a" and evt.CmdDown(): self.aligner.undo() else: - super(ThreeDScene, self).OnKeyDown(evt) + super().OnKeyDown(evt) self.aligner.scene_3d.renderer.reset_camera_clipping_range() self.aligner.scene_3d.render() @@ -161,7 +161,7 @@ def OnKeyDown(self, evt): class FlatScene(Scene): def OnKeyDown(self, event): #emulate behavior in QT - lookup = dict((i, (chr(i), None)) for i in range(256)) + lookup = {i: (chr(i), None) for i in range(256)} lookup[315] = ('', 'Up') lookup[314] = ('', 'Left') lookup[316] = ('', 'Right') @@ -261,7 +261,7 @@ class Axis(HasTraits): point_size = DelegatesTo('parent') def __init__(self, **kwargs): - super(Axis, self).__init__(**kwargs) + super().__init__(**kwargs) self.slab self.outline self.ipw_3d @@ -617,7 +617,7 @@ class XAxis(Axis): axis = 0 scene = DelegatesTo('parent', 'scene_x') def _outline_default(self): - surf = super(XAxis, self)._outline_default() + surf = super()._outline_default() surf.children[0].filter.transform.rotate_x(-90) surf.children[0].filter.transform.rotate_y(-90) return surf @@ -627,7 +627,7 @@ class YAxis(Axis): invert = True scene = DelegatesTo('parent', 'scene_y') def _outline_default(self): - surf = super(YAxis, self)._outline_default() + surf = super()._outline_default() surf.children[0].filter.transform.rotate_y(90) surf.children[0].filter.transform.rotate_x(90) return surf @@ -700,7 +700,7 @@ def __init__(self, pts, polys, epi, xfm=None, xfmtype='magnet', **traits): self.pts, self.polys = pts, polys self._undolist = [] self._redo = None - super(Align, self).__init__(**traits) + super().__init__(**traits) def load_epi(self, epifilename, xfm=None, xfmtype="magnet"): """Loads the EPI image from the specified epifilename. diff --git a/cortex/quickflat/composite.py b/cortex/quickflat/composite.py index b12104911..e0e0a14d8 100644 --- a/cortex/quickflat/composite.py +++ b/cortex/quickflat/composite.py @@ -580,7 +580,7 @@ def add_cutout(fig, name, dataview, layers=None, height=None, extents=None, over linewidth=2)) co = svgobject.get_texture('cutouts', height, labels=False, **svg_kws)[..., 0] if not np.any(co): - raise Exception('No pixels in cutout region {}!'.format(name)) + raise Exception(f'No pixels in cutout region {name}!') # Bounding box indices LL, RR, BB, TT = np.nan, np.nan, np.nan, np.nan @@ -594,7 +594,7 @@ def add_cutout(fig, name, dataview, layers=None, height=None, extents=None, over raise Exception("Shape mismatch btw cutout and data!") if any([np.abs(aa - bb) > 0 and np.abs(aa - bb) < 2 for aa, bb in zip(im.shape, co.shape)]): from scipy.misc import imresize - print('Resizing! {} to {}'.format(co.shape, im.shape[:2])) + print(f'Resizing! {co.shape} to {im.shape[:2]}') layer_cutout = imresize(co, im.shape[:2]).astype(np.float32)/255. else: layer_cutout = copy.copy(co) diff --git a/cortex/quickflat/utils.py b/cortex/quickflat/utils.py index ab834c0e3..8bcecafa3 100644 --- a/cortex/quickflat/utils.py +++ b/cortex/quickflat/utils.py @@ -129,7 +129,7 @@ def get_flatmask(subject, height=1024, recache=False): Recache the intermediate files? Can resolve some issues but is slower. """ cachedir = db.get_cache(subject) - cachefile = os.path.join(cachedir, "flatmask_{h}.npz".format(h=height)) + cachefile = os.path.join(cachedir, f"flatmask_{height}.npz") if not os.path.exists(cachefile) or recache: mask, extents = _make_flatmask(subject, height=height) @@ -250,8 +250,8 @@ def _convert_svg_kwargs(kwargs): #dash_capstyle # ADD ME? #dash_joinstyle # ADD ME? ) - out = dict((svg_style_key_mapping[k], svg_style_value_mapping[k](v)) - for k,v in kwargs.items() if v is not None) + out = {svg_style_key_mapping[k]: svg_style_value_mapping[k](v) + for k,v in kwargs.items() if v is not None} return out def _parse_defaults(section): @@ -290,7 +290,7 @@ def _get_images(fig): """Get all images in a given matplotlib axis""" from matplotlib.image import AxesImage _, ax = _get_fig_and_ax(fig) - images = dict((x.get_label(), x) for x in ax.get_children() if isinstance(x, AxesImage)) + images = {x.get_label(): x for x in ax.get_children() if isinstance(x, AxesImage)} return images def _get_extents(fig): diff --git a/cortex/rois.py b/cortex/rois.py index e9553c90b..3a60cdd2e 100644 --- a/cortex/rois.py +++ b/cortex/rois.py @@ -15,7 +15,7 @@ from .utils import add_roi from . import quickflat -class ROIpack(object): +class ROIpack: def __init__(self, subject, roifile): self.subject = subject self.roifile = roifile @@ -58,7 +58,7 @@ def load_roifile(self): def to_npz(self, filename): """Saves npz file containing ROI masks. """ - roidata = dict([(name,vd.data) for name,vd in self.rois.items()]) + roidata = {name:vd.data for name,vd in self.rois.items()} np.savez(filename, **roidata) def to_svg(self, open_inkscape=False, filename=None): diff --git a/cortex/segment.py b/cortex/segment.py index 3d5c24808..2414da27e 100644 --- a/cortex/segment.py +++ b/cortex/segment.py @@ -6,7 +6,6 @@ import numpy as np import subprocess as sp import multiprocessing as mp -from builtins import input from . import formats from . import blender diff --git a/cortex/svgoverlay.py b/cortex/svgoverlay.py index 9ae7ea3be..47135cac2 100644 --- a/cortex/svgoverlay.py +++ b/cortex/svgoverlay.py @@ -9,7 +9,6 @@ import subprocess as sp from matplotlib.path import Path from scipy.spatial import cKDTree -from builtins import zip, str from looseversion import LooseVersion @@ -27,7 +26,7 @@ cwd = os.path.abspath(os.path.split(__file__)[0]) -class SVGOverlay(object): +class SVGOverlay: """Object to represent all vector graphic overlays (rois, sulci, etc) stored in an svg file This object facilitates interaction with the information in the overlays.svg files @@ -312,7 +311,7 @@ def get_texture(self, layer_name, height, name=None, background=None, labels=Tru f" (stderr: {stderr})") return im -class Overlay(object): +class Overlay: """Class to represent a single layer of an SVG file """ def __init__(self, svgobject, layer): @@ -385,7 +384,7 @@ def add_shape(self, name, pngdata=None, add_path=True): #except: # xml.write(etree.tostring(svg, encoding=str, pretty_print=True)) # python3.X -class Labels(object): +class Labels: def __init__(self, overlay): self.overlay = overlay self.layer = _find_layer(self.overlay.layer, "labels") @@ -456,7 +455,7 @@ def visible(self, value): self.text_style['display'] = 'none' self.set() -class Shape(object): +class Shape: def __init__(self, layer, height, override_style=True): self.layer = layer self.height = height diff --git a/cortex/utils.py b/cortex/utils.py index 6ed7ab520..386b118e8 100644 --- a/cortex/utils.py +++ b/cortex/utils.py @@ -782,7 +782,7 @@ def get_roi_masks(subject, xfmname, roi_list=None, gm_sampler='cortical', split_ else: roi_verts = get_roi_verts(subject, roi=None, mask=use_mapper, overlay_file=overlay_file) missing = [r for r in roi_list if not r in roi_verts.keys()+['Cortex']] - roi_verts = dict((roi, verts) for roi, verts in roi_verts.items() if roi in roi_list) + roi_verts = {roi: verts for roi, verts in roi_verts.items() if roi in roi_list} roi_list = list(set(roi_list)-set(missing)) print('Requested ROI(s) {} not found in overlays.svg!'.format(missing)) # Get (a) indices for nearest vertex to each voxel @@ -1153,7 +1153,7 @@ def get_cmap(name): cmapdir = config.get('webgl', 'colormaps') colormaps = os.listdir(cmapdir) colormaps = sorted([c for c in colormaps if '.png' in c]) - colormaps = dict((c[:-4], os.path.join(cmapdir, c)) for c in colormaps) + colormaps = {c[:-4]: os.path.join(cmapdir, c) for c in colormaps} if name in colormaps: I = plt.imread(colormaps[name]) cmap = colors.ListedColormap(np.squeeze(I), name=name) diff --git a/cortex/xfm.py b/cortex/xfm.py index b8d5e95cf..de023ce58 100644 --- a/cortex/xfm.py +++ b/cortex/xfm.py @@ -4,7 +4,7 @@ import numpy as np import subprocess -class Transform(object): +class Transform: ''' A standard affine transform. Typically holds a transform from anatomical magnet space to epi file space. From 6077aa44ff226f5b6d35e4c38f3c625f4926f731 Mon Sep 17 00:00:00 2001 From: Aditya Vaidya Date: Wed, 12 Aug 2026 17:26:56 -0700 Subject: [PATCH 2/2] utils: fix get_roi_masks crash in missing-ROI fallback This happens whenever fail_for_missing_rois=False and a requested ROI isn't in overlays.svg. --- cortex/tests/test_utils.py | 14 ++++++++++++++ cortex/utils.py | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cortex/tests/test_utils.py b/cortex/tests/test_utils.py index 22ee0c937..8fb07b4a7 100644 --- a/cortex/tests/test_utils.py +++ b/cortex/tests/test_utils.py @@ -74,3 +74,17 @@ def fake_retrieve(url, dest): assert "fsaverage" in cortex.db.subjects cortex.utils.download_subject(subject_id='fsaverage', download_again=True) assert mock_retrieve.call_count == 2 + + +def test_get_roi_masks_missing_roi_does_not_fail_when_not_required(): + # When fail_for_missing_rois=False and a requested ROI isn't in + # overlays.svg, get_roi_masks falls back to computing the missing-ROI + # list from all available ROIs. That fallback used to crash with + # `TypeError: unsupported operand type(s) for +: 'dict_keys' and 'list'` + # because dict.keys() (a dict_keys view) doesn't support `+` with a list. + result = cortex.utils.get_roi_masks( + "S1", "fullhead", roi_list=["V1", "NotARealROI"], + fail_for_missing_rois=False, + ) + assert "V1" in result + assert "NotARealROI" not in result diff --git a/cortex/utils.py b/cortex/utils.py index 386b118e8..4a2adea79 100644 --- a/cortex/utils.py +++ b/cortex/utils.py @@ -781,7 +781,7 @@ def get_roi_masks(subject, xfmname, roi_list=None, gm_sampler='cortical', split_ raise KeyError("Requested ROI {} not found in overlays.svg!".format(key)) else: roi_verts = get_roi_verts(subject, roi=None, mask=use_mapper, overlay_file=overlay_file) - missing = [r for r in roi_list if not r in roi_verts.keys()+['Cortex']] + missing = [r for r in roi_list if not r in list(roi_verts.keys())+['Cortex']] roi_verts = {roi: verts for roi, verts in roi_verts.items() if roi in roi_list} roi_list = list(set(roi_list)-set(missing)) print('Requested ROI(s) {} not found in overlays.svg!'.format(missing))