10
10
from __future__ import annotations
11
11
12
12
import io
13
+ import os
14
+ import typing as ty
13
15
from copy import deepcopy
14
16
from typing import Type
15
17
from urllib import request
18
20
from .filename_parser import TypesFilenamesError , splitext_addext , types_filenames
19
21
from .openers import ImageOpener
20
22
23
+ FileSpec = ty .Union [str , os .PathLike ]
24
+ FileMap = ty .Mapping [str , FileHolder ]
25
+ FileSniff = ty .Tuple [bytes , str ]
26
+
21
27
22
28
class ImageFileError (Exception ):
23
29
pass
@@ -41,10 +47,10 @@ def from_header(klass, header=None):
41
47
)
42
48
43
49
@classmethod
44
- def from_fileobj (klass , fileobj ):
50
+ def from_fileobj (klass , fileobj : io . IOBase ):
45
51
raise NotImplementedError
46
52
47
- def write_to (self , fileobj ):
53
+ def write_to (self , fileobj : io . IOBase ):
48
54
raise NotImplementedError
49
55
50
56
def __eq__ (self , other ):
@@ -53,7 +59,7 @@ def __eq__(self, other):
53
59
def __ne__ (self , other ):
54
60
return not self == other
55
61
56
- def copy (self ):
62
+ def copy (self ) -> FileBasedHeader :
57
63
"""Copy object to independent representation
58
64
59
65
The copy should not be affected by any changes to the original
@@ -155,7 +161,12 @@ class FileBasedImage:
155
161
makeable : bool = True # Used in test code
156
162
rw : bool = True # Used in test code
157
163
158
- def __init__ (self , header = None , extra = None , file_map = None ):
164
+ def __init__ (
165
+ self ,
166
+ header : FileBasedHeader | ty .Mapping | None = None ,
167
+ extra : ty .Mapping | None = None ,
168
+ file_map : FileMap | None = None ,
169
+ ):
159
170
"""Initialize image
160
171
161
172
The image is a combination of (header), with
@@ -182,14 +193,14 @@ def __init__(self, header=None, extra=None, file_map=None):
182
193
self .file_map = file_map
183
194
184
195
@property
185
- def header (self ):
196
+ def header (self ) -> FileBasedHeader :
186
197
return self ._header
187
198
188
199
def __getitem__ (self , key ):
189
200
"""No slicing or dictionary interface for images"""
190
201
raise TypeError ('Cannot slice image objects.' )
191
202
192
- def get_filename (self ):
203
+ def get_filename (self ) -> str | None :
193
204
"""Fetch the image filename
194
205
195
206
Parameters
@@ -210,7 +221,7 @@ def get_filename(self):
210
221
characteristic_type = self .files_types [0 ][0 ]
211
222
return self .file_map [characteristic_type ].filename
212
223
213
- def set_filename (self , filename ):
224
+ def set_filename (self , filename : str ):
214
225
"""Sets the files in the object from a given filename
215
226
216
227
The different image formats may check whether the filename has
@@ -228,16 +239,16 @@ def set_filename(self, filename):
228
239
self .file_map = self .__class__ .filespec_to_file_map (filename )
229
240
230
241
@classmethod
231
- def from_filename (klass , filename ):
242
+ def from_filename (klass , filename : FileSpec ):
232
243
file_map = klass .filespec_to_file_map (filename )
233
244
return klass .from_file_map (file_map )
234
245
235
246
@classmethod
236
- def from_file_map (klass , file_map ):
247
+ def from_file_map (klass , file_map : FileMap ):
237
248
raise NotImplementedError
238
249
239
250
@classmethod
240
- def filespec_to_file_map (klass , filespec ):
251
+ def filespec_to_file_map (klass , filespec : FileSpec ):
241
252
"""Make `file_map` for this class from filename `filespec`
242
253
243
254
Class method
@@ -271,7 +282,7 @@ def filespec_to_file_map(klass, filespec):
271
282
file_map [key ] = FileHolder (filename = fname )
272
283
return file_map
273
284
274
- def to_filename (self , filename , ** kwargs ):
285
+ def to_filename (self , filename : FileSpec , ** kwargs ):
275
286
r"""Write image to files implied by filename string
276
287
277
288
Parameters
@@ -290,11 +301,11 @@ def to_filename(self, filename, **kwargs):
290
301
self .file_map = self .filespec_to_file_map (filename )
291
302
self .to_file_map (** kwargs )
292
303
293
- def to_file_map (self , file_map = None , ** kwargs ):
304
+ def to_file_map (self , file_map : FileMap | None = None , ** kwargs ):
294
305
raise NotImplementedError
295
306
296
307
@classmethod
297
- def make_file_map (klass , mapping = None ):
308
+ def make_file_map (klass , mapping : ty . Mapping [ str , str | io . IOBase ] | None = None ):
298
309
"""Class method to make files holder for this image type
299
310
300
311
Parameters
@@ -327,7 +338,7 @@ def make_file_map(klass, mapping=None):
327
338
load = from_filename
328
339
329
340
@classmethod
330
- def instance_to_filename (klass , img , filename ):
341
+ def instance_to_filename (klass , img : FileBasedImage , filename : FileSpec ):
331
342
"""Save `img` in our own format, to name implied by `filename`
332
343
333
344
This is a class method
@@ -343,7 +354,7 @@ def instance_to_filename(klass, img, filename):
343
354
img .to_filename (filename )
344
355
345
356
@classmethod
346
- def from_image (klass , img ):
357
+ def from_image (klass , img : FileBasedImage ):
347
358
"""Class method to create new instance of own class from `img`
348
359
349
360
Parameters
@@ -359,7 +370,12 @@ def from_image(klass, img):
359
370
raise NotImplementedError ()
360
371
361
372
@classmethod
362
- def _sniff_meta_for (klass , filename , sniff_nbytes , sniff = None ):
373
+ def _sniff_meta_for (
374
+ klass ,
375
+ filename : FileSpec ,
376
+ sniff_nbytes : int ,
377
+ sniff : FileSniff | None = None ,
378
+ ):
363
379
"""Sniff metadata for image represented by `filename`
364
380
365
381
Parameters
@@ -404,7 +420,12 @@ def _sniff_meta_for(klass, filename, sniff_nbytes, sniff=None):
404
420
return (binaryblock , meta_fname )
405
421
406
422
@classmethod
407
- def path_maybe_image (klass , filename , sniff = None , sniff_max = 1024 ):
423
+ def path_maybe_image (
424
+ klass ,
425
+ filename : FileSpec ,
426
+ sniff : FileSniff | None = None ,
427
+ sniff_max : int = 1024 ,
428
+ ):
408
429
"""Return True if `filename` may be image matching this class
409
430
410
431
Parameters
@@ -547,7 +568,7 @@ def from_bytes(klass, bytestring: bytes):
547
568
548
569
Parameters
549
570
----------
550
- bstring : bytes
571
+ bytestring : bytes
551
572
Byte string containing the on-disk representation of an image
552
573
"""
553
574
return klass .from_stream (io .BytesIO (bytestring ))
@@ -571,7 +592,7 @@ def to_bytes(self, **kwargs) -> bytes:
571
592
return bio .getvalue ()
572
593
573
594
@classmethod
574
- def from_url (klass , url , timeout = 5 ):
595
+ def from_url (klass , url : str | request . Request , timeout : float = 5 ):
575
596
"""Retrieve and load an image from a URL
576
597
577
598
Class method
0 commit comments