Skip to content

Commit ef06c65

Browse files
committed
TYP: Annotated filename_parser, move typedefs from filebasedimages
1 parent d3a892f commit ef06c65

File tree

2 files changed

+43
-34
lines changed

2 files changed

+43
-34
lines changed

nibabel/filebasedimages.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,22 @@
1010
from __future__ import annotations
1111

1212
import io
13-
import os
1413
import typing as ty
1514
from copy import deepcopy
1615
from typing import Type
1716
from urllib import request
1817

1918
from .fileholders import FileHolder, FileMap
20-
from .filename_parser import TypesFilenamesError, splitext_addext, types_filenames
19+
from .filename_parser import (
20+
ExtensionSpec,
21+
FileSpec,
22+
TypesFilenamesError,
23+
_stringify_path,
24+
splitext_addext,
25+
types_filenames,
26+
)
2127
from .openers import ImageOpener
2228

23-
FileSpec = ty.Union[str, os.PathLike]
2429
FileSniff = ty.Tuple[bytes, str]
2530

2631
ImgT = ty.TypeVar('ImgT', bound='FileBasedImage')
@@ -159,7 +164,7 @@ class FileBasedImage:
159164
header_class: Type[FileBasedHeader] = FileBasedHeader
160165
_header: FileBasedHeader
161166
_meta_sniff_len: int = 0
162-
files_types: tuple[tuple[str, str | None], ...] = (('image', None),)
167+
files_types: tuple[ExtensionSpec, ...] = (('image', None),)
163168
valid_exts: tuple[str, ...] = ()
164169
_compressed_suffixes: tuple[str, ...] = ()
165170

@@ -410,7 +415,7 @@ def _sniff_meta_for(
410415
t_fnames = types_filenames(
411416
filename, klass.files_types, trailing_suffixes=klass._compressed_suffixes
412417
)
413-
meta_fname = t_fnames.get('header', filename)
418+
meta_fname = t_fnames.get('header', _stringify_path(filename))
414419

415420
# Do not re-sniff if it would be from the same file
416421
if sniff is not None and sniff[1] == meta_fname:

nibabel/filename_parser.py

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77
#
88
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
99
"""Create filename pairs, triplets etc, with expected extensions"""
10+
from __future__ import annotations
1011

1112
import os
12-
import pathlib
13+
import typing as ty
14+
15+
FileSpec = ty.Union[str, os.PathLike[str]]
16+
ExtensionSpec = ty.Tuple[str, str | None]
1317

1418

1519
class TypesFilenamesError(Exception):
1620
pass
1721

1822

19-
def _stringify_path(filepath_or_buffer):
23+
def _stringify_path(filepath_or_buffer: FileSpec) -> str:
2024
"""Attempt to convert a path-like object to a string.
2125
2226
Parameters
@@ -29,30 +33,21 @@ def _stringify_path(filepath_or_buffer):
2933
3034
Notes
3135
-----
32-
Objects supporting the fspath protocol (python 3.6+) are coerced
33-
according to its __fspath__ method.
34-
For backwards compatibility with older pythons, pathlib.Path objects
35-
are specially coerced.
36-
Any other object is passed through unchanged, which includes bytes,
37-
strings, buffers, or anything else that's not even path-like.
38-
39-
Copied from:
36+
Initially copied from:
4037
https://github.com/pandas-dev/pandas/blob/325dd686de1589c17731cf93b649ed5ccb5a99b4/pandas/io/common.py#L131-L160
4138
"""
42-
if hasattr(filepath_or_buffer, '__fspath__'):
39+
if isinstance(filepath_or_buffer, os.PathLike):
4340
return filepath_or_buffer.__fspath__()
44-
elif isinstance(filepath_or_buffer, pathlib.Path):
45-
return str(filepath_or_buffer)
4641
return filepath_or_buffer
4742

4843

4944
def types_filenames(
50-
template_fname,
51-
types_exts,
52-
trailing_suffixes=('.gz', '.bz2'),
53-
enforce_extensions=True,
54-
match_case=False,
55-
):
45+
template_fname: FileSpec,
46+
types_exts: ty.Sequence[ExtensionSpec],
47+
trailing_suffixes: ty.Sequence[str] = ('.gz', '.bz2'),
48+
enforce_extensions: bool = True,
49+
match_case: bool = False,
50+
) -> dict[str, str]:
5651
"""Return filenames with standard extensions from template name
5752
5853
The typical case is returning image and header filenames for an
@@ -153,12 +148,12 @@ def types_filenames(
153148
# we've found .IMG as the extension, we want .HDR as the matching
154149
# one. Let's only do this when the extension is all upper or all
155150
# lower case.
156-
proc_ext = lambda s: s
151+
proc_ext: ty.Callable[[str], str] = lambda s: s
157152
if found_ext:
158153
if found_ext == found_ext.upper():
159-
proc_ext = lambda s: s.upper()
154+
proc_ext = str.upper
160155
elif found_ext == found_ext.lower():
161-
proc_ext = lambda s: s.lower()
156+
proc_ext = str.lower
162157
for name, ext in types_exts:
163158
if name == direct_set_name:
164159
tfns[name] = template_fname
@@ -172,7 +167,12 @@ def types_filenames(
172167
return tfns
173168

174169

175-
def parse_filename(filename, types_exts, trailing_suffixes, match_case=False):
170+
def parse_filename(
171+
filename: FileSpec,
172+
types_exts: ty.Sequence[ExtensionSpec],
173+
trailing_suffixes: ty.Sequence[str],
174+
match_case: bool = False,
175+
) -> tuple[str, str, str | None, str | None]:
176176
"""Split filename into fileroot, extension, trailing suffix; guess type.
177177
178178
Parameters
@@ -231,9 +231,9 @@ def parse_filename(filename, types_exts, trailing_suffixes, match_case=False):
231231
break
232232
guessed_name = None
233233
found_ext = None
234-
for name, ext in types_exts:
235-
if ext and endswith(filename, ext):
236-
extpos = -len(ext)
234+
for name, type_ext in types_exts:
235+
if type_ext and endswith(filename, type_ext):
236+
extpos = -len(type_ext)
237237
found_ext = filename[extpos:]
238238
filename = filename[:extpos]
239239
guessed_name = name
@@ -243,15 +243,19 @@ def parse_filename(filename, types_exts, trailing_suffixes, match_case=False):
243243
return (filename, found_ext, ignored, guessed_name)
244244

245245

246-
def _endswith(whole, end):
246+
def _endswith(whole: str, end: str) -> bool:
247247
return whole.endswith(end)
248248

249249

250-
def _iendswith(whole, end):
250+
def _iendswith(whole: str, end: str) -> bool:
251251
return whole.lower().endswith(end.lower())
252252

253253

254-
def splitext_addext(filename, addexts=('.gz', '.bz2', '.zst'), match_case=False):
254+
def splitext_addext(
255+
filename: FileSpec,
256+
addexts: ty.Sequence[str] = ('.gz', '.bz2', '.zst'),
257+
match_case: bool = False,
258+
) -> tuple[str, str, str]:
255259
"""Split ``/pth/fname.ext.gz`` into ``/pth/fname, .ext, .gz``
256260
257261
where ``.gz`` may be any of passed `addext` trailing suffixes.

0 commit comments

Comments
 (0)