Skip to content

Commit

Permalink
ENH: Add type annotations to pacify mypy
Browse files Browse the repository at this point in the history
  • Loading branch information
effigies committed Jan 2, 2023
1 parent 9ef7aab commit 8b5cf92
Show file tree
Hide file tree
Showing 21 changed files with 79 additions and 73 deletions.
13 changes: 8 additions & 5 deletions nibabel/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
can be loaded with and without a default flip, so the saved zoom will not
constrain the affine.
"""
from __future__ import annotations

from typing import Type

import numpy as np

Expand Down Expand Up @@ -131,7 +134,7 @@
('glmax', 'i4'),
('glmin', 'i4'),
]
data_history_dtd = [
data_history_dtd: list[tuple[str, str] | tuple[str, str, tuple[int, ...]]] = [
('descrip', 'S80'),
('aux_file', 'S24'),
('orient', 'S1'),
Expand Down Expand Up @@ -892,11 +895,11 @@ def may_contain_header(klass, binaryblock):
class AnalyzeImage(SpatialImage):
"""Class for basic Analyze format image"""

header_class = AnalyzeHeader
header_class: Type[AnalyzeHeader] = AnalyzeHeader
_meta_sniff_len = header_class.sizeof_hdr
files_types = (('image', '.img'), ('header', '.hdr'))
valid_exts = ('.img', '.hdr')
_compressed_suffixes = ('.gz', '.bz2', '.zst')
files_types: tuple[tuple[str, str], ...] = (('image', '.img'), ('header', '.hdr'))
valid_exts: tuple[str, ...] = ('.img', '.hdr')
_compressed_suffixes: tuple[str, ...] = ('.gz', '.bz2', '.zst')

makeable = True
rw = True
Expand Down
2 changes: 1 addition & 1 deletion nibabel/benchmarks/bench_arrayproxy_slicing.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

# if memory_profiler is installed, we get memory usage results
try:
from memory_profiler import memory_usage
from memory_profiler import memory_usage # type: ignore
except ImportError:
memory_usage = None

Expand Down
7 changes: 4 additions & 3 deletions nibabel/brikhead.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
am aware) always be >= 1. This permits sub-brick indexing common in AFNI
programs (e.g., example4d+orig'[0]').
"""
from __future__ import annotations

import os
import re
Expand Down Expand Up @@ -476,9 +477,9 @@ class AFNIImage(SpatialImage):
True
"""

header_class = AFNIHeader
valid_exts = ('.brik', '.head')
files_types = (('image', '.brik'), ('header', '.head'))
header_class: type = AFNIHeader
valid_exts: tuple[str, ...] = ('.brik', '.head')
files_types: tuple[tuple[str, str], ...] = (('image', '.brik'), ('header', '.head'))
_compressed_suffixes = ('.gz', '.bz2', '.Z', '.zst')
makeable = False
rw = False
Expand Down
3 changes: 2 additions & 1 deletion nibabel/casting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Most routines work round some numpy oddities in floating point precision and
casting. Others work round numpy casting to and from python ints
"""
from __future__ import annotations

import warnings
from numbers import Integral
Expand Down Expand Up @@ -110,7 +111,7 @@ def float_to_int(arr, int_type, nan2zero=True, infmax=False):


# Cache range values
_SHARED_RANGES = {}
_SHARED_RANGES : dict[tuple[type, type], tuple[np.number, np.number]] = {}


def shared_range(flt_type, int_type):
Expand Down
2 changes: 1 addition & 1 deletion nibabel/cmdline/dicomfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class dummy_fuse:


try:
import fuse
import fuse # type: ignore

uid = os.getuid()
gid = os.getgid()
Expand Down
4 changes: 2 additions & 2 deletions nibabel/externals/netcdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,7 @@ def __setattr__(self, attr, value):
pass
self.__dict__[attr] = value

@property
def isrec(self):
"""Returns whether the variable has a record dimension or not.
Expand All @@ -881,16 +882,15 @@ def isrec(self):
"""
return bool(self.data.shape) and not self._shape[0]
isrec = property(isrec)

@property
def shape(self):
"""Returns the shape tuple of the data variable.
This is a read-only attribute and can not be modified in the
same manner of other numpy arrays.
"""
return self.data.shape
shape = property(shape)

def getValue(self):
"""
Expand Down
15 changes: 8 additions & 7 deletions nibabel/filebasedimages.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""Common interface for any image format--volume or surface, binary or xml."""
from __future__ import annotations

import io
from copy import deepcopy
Expand Down Expand Up @@ -144,14 +145,14 @@ class FileBasedImage:
work.
"""

header_class = FileBasedHeader
_meta_sniff_len = 0
files_types = (('image', None),)
valid_exts = ()
_compressed_suffixes = ()
header_class: type = FileBasedHeader
_meta_sniff_len: int = 0
files_types: tuple[tuple[str, str | None], ...] = (('image', None),)
valid_exts: tuple[str, ...] = ()
_compressed_suffixes: tuple[str, ...] = ()

makeable = True # Used in test code
rw = True # Used in test code
makeable: bool = True # Used in test code
rw: bool = True # Used in test code

def __init__(self, header=None, extra=None, file_map=None):
"""Initialize image
Expand Down
13 changes: 8 additions & 5 deletions nibabel/gifti/gifti.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
The Gifti specification was (at time of writing) available as a PDF download
from http://www.nitrc.org/projects/gifti/
"""
from __future__ import annotations

import base64
import sys
import warnings
from typing import Type

import numpy as np

Expand Down Expand Up @@ -577,7 +579,7 @@ class GiftiImage(xml.XmlSerializable, SerializableImage):
# The parser will in due course be a GiftiImageParser, but we can't set
# that now, because it would result in a circular import. We set it after
# the class has been defined, at the end of the class definition.
parser = None
parser: Type[xml.XmlParser]

def __init__(
self,
Expand Down Expand Up @@ -832,17 +834,18 @@ def _to_xml_element(self):
GIFTI.append(dar._to_xml_element())
return GIFTI

def to_xml(self, enc='utf-8'):
def to_xml(self, enc='utf-8') -> bytes:
"""Return XML corresponding to image content"""
header = b"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE GIFTI SYSTEM "http://www.nitrc.org/frs/download.php/115/gifti.dtd">
"""
return header + super().to_xml(enc)

# Avoid the indirection of going through to_file_map
to_bytes = to_xml
def to_bytes(self, enc='utf-8'):
return self.to_xml(enc=enc)

def to_file_map(self, file_map=None):
def to_file_map(self, file_map=None, enc='utf-8'):
"""Save the current image to the specified file_map
Parameters
Expand All @@ -858,7 +861,7 @@ def to_file_map(self, file_map=None):
if file_map is None:
file_map = self.file_map
with file_map['image'].get_prepare_fileobj('wb') as f:
f.write(self.to_xml())
f.write(self.to_xml(enc=enc))

@classmethod
def from_file_map(klass, file_map, buffer_size=35000000, mmap=True):
Expand Down
5 changes: 3 additions & 2 deletions nibabel/minc1.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
"""Read MINC1 format images"""
from __future__ import annotations

from numbers import Integral

Expand Down Expand Up @@ -305,11 +306,11 @@ class Minc1Image(SpatialImage):
load.
"""

header_class = Minc1Header
header_class: type = Minc1Header
_meta_sniff_len = 4
valid_exts = ('.mnc',)
files_types = (('image', '.mnc'),)
_compressed_suffixes = ('.gz', '.bz2', '.zst')
_compressed_suffixes: tuple[str, ...] = ('.gz', '.bz2', '.zst')

makeable = True
rw = False
Expand Down
6 changes: 4 additions & 2 deletions nibabel/minc2.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
mincstats my_funny.mnc
"""
from __future__ import annotations

import numpy as np

from .minc1 import Minc1File, Minc1Image, MincError, MincHeader
Expand Down Expand Up @@ -148,14 +150,14 @@ class Minc2Image(Minc1Image):
"""

# MINC2 does not do compressed whole files
_compressed_suffixes = ()
_compressed_suffixes: tuple[str, ...] = ()
header_class = Minc2Header

@classmethod
def from_file_map(klass, file_map, *, mmap=True, keep_file_open=None):
# Import of h5py might take awhile for MPI-enabled builds
# So we are importing it here "on demand"
import h5py
import h5py # type: ignore

holder = file_map['image']
if holder.filename is None:
Expand Down
2 changes: 0 additions & 2 deletions nibabel/nicom/dicomwrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,6 @@ class Wrapper:
is_multiframe = False
b_matrix = None
q_vector = None
b_value = None
b_vector = None

def __init__(self, dcm_data):
"""Initialize wrapper
Expand Down
14 changes: 7 additions & 7 deletions nibabel/nifti1.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
NIfTI1 format defined at http://nifti.nimh.nih.gov/nifti-1/
"""
from __future__ import annotations

import warnings
from io import BytesIO
from typing import Type

import numpy as np
import numpy.linalg as npl
Expand Down Expand Up @@ -86,8 +89,8 @@
# datatypes not in analyze format, with codes
if have_binary128():
# Only enable 128 bit floats if we really have IEEE binary 128 longdoubles
_float128t = np.longdouble
_complex256t = np.longcomplex
_float128t: Type[np.generic] = np.longdouble
_complex256t: Type[np.generic] = np.longcomplex
else:
_float128t = np.void
_complex256t = np.void
Expand Down Expand Up @@ -1813,7 +1816,7 @@ class Nifti1PairHeader(Nifti1Header):
class Nifti1Pair(analyze.AnalyzeImage):
"""Class for NIfTI1 format image, header pair"""

header_class = Nifti1PairHeader
header_class: Type[Nifti1Header] = Nifti1PairHeader
_meta_sniff_len = header_class.sizeof_hdr
rw = True

Expand Down Expand Up @@ -1844,9 +1847,7 @@ def __init__(self, dataobj, affine, header=None, extra=None, file_map=None, dtyp
self._affine2header()

# Copy docstring
__init__.__doc__ = (
analyze.AnalyzeImage.__init__.__doc__
+ """
__init__.__doc__ = f"""{analyze.AnalyzeImage.__init__.__doc__}
Notes
-----
Expand All @@ -1859,7 +1860,6 @@ def __init__(self, dataobj, affine, header=None, extra=None, file_map=None, dtyp
:meth:`set_qform` methods can be used to update the codes after an image
has been created - see those methods, and the :ref:`manual
<default-sform-qform-codes>` for more details. """
)

def update_header(self):
"""Harmonize header with image data and affine
Expand Down
2 changes: 1 addition & 1 deletion nibabel/openers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

# is indexed_gzip present and modern?
try:
import indexed_gzip as igzip
import indexed_gzip as igzip # type: ignore

version = igzip.__version__

Expand Down
4 changes: 2 additions & 2 deletions nibabel/parrec.py
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,7 @@ def from_filename(
strict_sort=strict_sort,
)

load = from_filename
load = from_filename # type: ignore


load = PARRECImage.load
load = PARRECImage.from_filename
23 changes: 12 additions & 11 deletions nibabel/pydicom_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
without error, and always defines:
* have_dicom : True if we can import pydicom or dicom;
* pydicom : pydicom module or dicom module or None of not importable;
* pydicom : pydicom module or dicom module or None if not importable;
* read_file : ``read_file`` function if pydicom or dicom module is importable
else None;
* tag_for_keyword : ``tag_for_keyword`` function if pydicom or dicom module
Expand All @@ -19,26 +19,27 @@
A deprecated copy is available here for backward compatibility.
"""
from __future__ import annotations
from .optpkg import optional_package
from typing import Callable
from types import ModuleType

# Module has (apparently) unused imports; stop flake8 complaining
# flake8: noqa

from .deprecated import deprecate_with_version

have_dicom = True
pydicom = read_file = tag_for_keyword = Sequence = None
pydicom, have_dicom, _ = optional_package('pydicom')

try:
import pydicom
except ImportError:
have_dicom = False
else: # pydicom module available
read_file: Callable | None = None
tag_for_keyword: Callable | None = None
Sequence: type | None = None

if have_dicom:
# Values not imported by default
import pydicom.values
import pydicom.values # type: ignore
from pydicom.dicomio import read_file
from pydicom.sequence import Sequence

if have_dicom:
tag_for_keyword = pydicom.datadict.tag_for_keyword


Expand Down
3 changes: 2 additions & 1 deletion nibabel/spatialimages.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
>>> np.all(img3.get_fdata(dtype=np.float32) == data)
True
"""
from __future__ import annotations

import numpy as np

Expand Down Expand Up @@ -400,7 +401,7 @@ def slice_affine(self, slicer):
class SpatialImage(DataobjImage):
"""Template class for volumetric (3D/4D) images"""

header_class = SpatialHeader
header_class: type = SpatialHeader
ImageSlicer = SpatialFirstSlicer

def __init__(self, dataobj, affine, header=None, extra=None, file_map=None):
Expand Down
2 changes: 1 addition & 1 deletion nibabel/spm99analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def from_file_map(klass, file_map, *, mmap=True, keep_file_open=None):
contents = matf.read()
if len(contents) == 0:
return ret
import scipy.io as sio
import scipy.io as sio # type: ignore

mats = sio.loadmat(BytesIO(contents))
if 'mat' in mats: # this overrides a 'M', and includes any flip
Expand Down
Loading

0 comments on commit 8b5cf92

Please sign in to comment.