summaryrefslogtreecommitdiff
path: root/libmat2
diff options
context:
space:
mode:
authorjvoisin2018-10-12 11:58:01 +0200
committerjvoisin2018-10-12 14:32:09 +0200
commit2ba38dd2a18ab57ed7aac7ccdd6a42ff5e4d4eb7 (patch)
tree7fe800485f6ea47b21f63195c6dfc2f32e675bfe /libmat2
parentb832a5941458083dd6147efb652036552f95b786 (diff)
Bump mypy typing coverage
Diffstat (limited to 'libmat2')
-rw-r--r--libmat2/__init__.py5
-rw-r--r--libmat2/abstract.py4
-rw-r--r--libmat2/archive.py3
-rw-r--r--libmat2/audio.py28
-rw-r--r--libmat2/harmless.py4
-rw-r--r--libmat2/images.py20
-rw-r--r--libmat2/office.py6
-rw-r--r--libmat2/pdf.py3
-rw-r--r--libmat2/torrent.py2
9 files changed, 42 insertions, 33 deletions
diff --git a/libmat2/__init__.py b/libmat2/__init__.py
index fbb61bc..f55a14c 100644
--- a/libmat2/__init__.py
+++ b/libmat2/__init__.py
@@ -8,6 +8,7 @@ from typing import Dict, Optional
8 8
9# make pyflakes happy 9# make pyflakes happy
10assert Dict 10assert Dict
11assert Optional
11 12
12# A set of extension that aren't supported, despite matching a supported mimetype 13# A set of extension that aren't supported, despite matching a supported mimetype
13UNSUPPORTED_EXTENSIONS = { 14UNSUPPORTED_EXTENSIONS = {
@@ -36,7 +37,7 @@ DEPENDENCIES = {
36 'mutagen': 'Mutagen', 37 'mutagen': 'Mutagen',
37 } 38 }
38 39
39def _get_exiftool_path() -> Optional[str]: # pragma: no cover 40def _get_exiftool_path() -> str: # pragma: no cover
40 exiftool_path = '/usr/bin/exiftool' 41 exiftool_path = '/usr/bin/exiftool'
41 if os.path.isfile(exiftool_path): 42 if os.path.isfile(exiftool_path):
42 if os.access(exiftool_path, os.X_OK): 43 if os.access(exiftool_path, os.X_OK):
@@ -48,7 +49,7 @@ def _get_exiftool_path() -> Optional[str]: # pragma: no cover
48 if os.access(exiftool_path, os.X_OK): 49 if os.access(exiftool_path, os.X_OK):
49 return exiftool_path 50 return exiftool_path
50 51
51 return None 52 raise ValueError
52 53
53def check_dependencies() -> dict: 54def check_dependencies() -> dict:
54 ret = collections.defaultdict(bool) # type: Dict[str, bool] 55 ret = collections.defaultdict(bool) # type: Dict[str, bool]
diff --git a/libmat2/abstract.py b/libmat2/abstract.py
index 5bcaa69..0084796 100644
--- a/libmat2/abstract.py
+++ b/libmat2/abstract.py
@@ -1,6 +1,6 @@
1import abc 1import abc
2import os 2import os
3from typing import Set, Dict 3from typing import Set, Dict, Union
4 4
5assert Set # make pyflakes happy 5assert Set # make pyflakes happy
6 6
@@ -22,7 +22,7 @@ class AbstractParser(abc.ABC):
22 self.lightweight_cleaning = False 22 self.lightweight_cleaning = False
23 23
24 @abc.abstractmethod 24 @abc.abstractmethod
25 def get_meta(self) -> Dict[str, str]: 25 def get_meta(self) -> Dict[str, Union[str, dict]]:
26 pass # pragma: no cover 26 pass # pragma: no cover
27 27
28 @abc.abstractmethod 28 @abc.abstractmethod
diff --git a/libmat2/archive.py b/libmat2/archive.py
index 016142d..f788ecc 100644
--- a/libmat2/archive.py
+++ b/libmat2/archive.py
@@ -4,13 +4,14 @@ import tempfile
4import os 4import os
5import logging 5import logging
6import shutil 6import shutil
7from typing import Dict, Set, Pattern 7from typing import Dict, Set, Pattern, Union
8 8
9from . import abstract, UnknownMemberPolicy, parser_factory 9from . import abstract, UnknownMemberPolicy, parser_factory
10 10
11# Make pyflakes happy 11# Make pyflakes happy
12assert Set 12assert Set
13assert Pattern 13assert Pattern
14assert Union
14 15
15 16
16class ArchiveBasedAbstractParser(abstract.AbstractParser): 17class ArchiveBasedAbstractParser(abstract.AbstractParser):
diff --git a/libmat2/audio.py b/libmat2/audio.py
index b67f766..bfe7f79 100644
--- a/libmat2/audio.py
+++ b/libmat2/audio.py
@@ -2,6 +2,7 @@ import mimetypes
2import os 2import os
3import shutil 3import shutil
4import tempfile 4import tempfile
5from typing import Dict, Union
5 6
6import mutagen 7import mutagen
7 8
@@ -16,13 +17,13 @@ class MutagenParser(abstract.AbstractParser):
16 except mutagen.MutagenError: 17 except mutagen.MutagenError:
17 raise ValueError 18 raise ValueError
18 19
19 def get_meta(self): 20 def get_meta(self) -> Dict[str, Union[str, dict]]:
20 f = mutagen.File(self.filename) 21 f = mutagen.File(self.filename)
21 if f.tags: 22 if f.tags:
22 return {k:', '.join(v) for k, v in f.tags.items()} 23 return {k:', '.join(v) for k, v in f.tags.items()}
23 return {} 24 return {}
24 25
25 def remove_all(self): 26 def remove_all(self) -> bool:
26 shutil.copy(self.filename, self.output_filename) 27 shutil.copy(self.filename, self.output_filename)
27 f = mutagen.File(self.output_filename) 28 f = mutagen.File(self.output_filename)
28 f.delete() 29 f.delete()
@@ -33,8 +34,8 @@ class MutagenParser(abstract.AbstractParser):
33class MP3Parser(MutagenParser): 34class MP3Parser(MutagenParser):
34 mimetypes = {'audio/mpeg', } 35 mimetypes = {'audio/mpeg', }
35 36
36 def get_meta(self): 37 def get_meta(self) -> Dict[str, Union[str, dict]]:
37 metadata = {} 38 metadata = {} # type: Dict[str, Union[str, dict]]
38 meta = mutagen.File(self.filename).tags 39 meta = mutagen.File(self.filename).tags
39 for key in meta: 40 for key in meta:
40 metadata[key.rstrip(' \t\r\n\0')] = ', '.join(map(str, meta[key].text)) 41 metadata[key.rstrip(' \t\r\n\0')] = ', '.join(map(str, meta[key].text))
@@ -48,7 +49,7 @@ class OGGParser(MutagenParser):
48class FLACParser(MutagenParser): 49class FLACParser(MutagenParser):
49 mimetypes = {'audio/flac', 'audio/x-flac'} 50 mimetypes = {'audio/flac', 'audio/x-flac'}
50 51
51 def remove_all(self): 52 def remove_all(self) -> bool:
52 shutil.copy(self.filename, self.output_filename) 53 shutil.copy(self.filename, self.output_filename)
53 f = mutagen.File(self.output_filename) 54 f = mutagen.File(self.output_filename)
54 f.clear_pictures() 55 f.clear_pictures()
@@ -56,16 +57,21 @@ class FLACParser(MutagenParser):
56 f.save(deleteid3=True) 57 f.save(deleteid3=True)
57 return True 58 return True
58 59
59 def get_meta(self): 60 def get_meta(self) -> Dict[str, Union[str, dict]]:
60 meta = super().get_meta() 61 meta = super().get_meta()
61 for num, picture in enumerate(mutagen.File(self.filename).pictures): 62 for num, picture in enumerate(mutagen.File(self.filename).pictures):
62 name = picture.desc if picture.desc else 'Cover %d' % num 63 name = picture.desc if picture.desc else 'Cover %d' % num
64 extension = mimetypes.guess_extension(picture.mime)
65 if extension is None: # pragma: no cover
66 meta[name] = 'harmful data'
67 continue
68
63 _, fname = tempfile.mkstemp() 69 _, fname = tempfile.mkstemp()
70 fname = fname + extension
64 with open(fname, 'wb') as f: 71 with open(fname, 'wb') as f:
65 f.write(picture.data) 72 f.write(picture.data)
66 extension = mimetypes.guess_extension(picture.mime) 73 p, _ = parser_factory.get_parser(fname) # type: ignore
67 shutil.move(fname, fname + extension) 74 # Mypy chokes on ternaries :/
68 p, _ = parser_factory.get_parser(fname+extension) 75 meta[name] = p.get_meta() if p else 'harmful data' # type: ignore
69 meta[name] = p.get_meta() if p else 'harmful data' 76 os.remove(fname)
70 os.remove(fname + extension)
71 return meta 77 return meta
diff --git a/libmat2/harmless.py b/libmat2/harmless.py
index f646099..fad0ef8 100644
--- a/libmat2/harmless.py
+++ b/libmat2/harmless.py
@@ -1,5 +1,5 @@
1import shutil 1import shutil
2from typing import Dict 2from typing import Dict, Union
3from . import abstract 3from . import abstract
4 4
5 5
@@ -7,7 +7,7 @@ class HarmlessParser(abstract.AbstractParser):
7 """ This is the parser for filetypes that can not contain metadata. """ 7 """ This is the parser for filetypes that can not contain metadata. """
8 mimetypes = {'text/plain', 'image/x-ms-bmp'} 8 mimetypes = {'text/plain', 'image/x-ms-bmp'}
9 9
10 def get_meta(self) -> Dict[str, str]: 10 def get_meta(self) -> Dict[str, Union[str, dict]]:
11 return dict() 11 return dict()
12 12
13 def remove_all(self) -> bool: 13 def remove_all(self) -> bool:
diff --git a/libmat2/images.py b/libmat2/images.py
index 8f7a98d..a29cbb7 100644
--- a/libmat2/images.py
+++ b/libmat2/images.py
@@ -5,7 +5,7 @@ import os
5import shutil 5import shutil
6import tempfile 6import tempfile
7import re 7import re
8from typing import Set 8from typing import Set, Dict, Union
9 9
10import cairo 10import cairo
11 11
@@ -25,7 +25,7 @@ class _ImageParser(abstract.AbstractParser):
25 meta_whitelist = set() # type: Set[str] 25 meta_whitelist = set() # type: Set[str]
26 26
27 @staticmethod 27 @staticmethod
28 def __handle_problematic_filename(filename: str, callback) -> str: 28 def __handle_problematic_filename(filename: str, callback) -> bytes:
29 """ This method takes a filename with a problematic name, 29 """ This method takes a filename with a problematic name,
30 and safely applies it a `callback`.""" 30 and safely applies it a `callback`."""
31 tmpdirname = tempfile.mkdtemp() 31 tmpdirname = tempfile.mkdtemp()
@@ -35,7 +35,7 @@ class _ImageParser(abstract.AbstractParser):
35 shutil.rmtree(tmpdirname) 35 shutil.rmtree(tmpdirname)
36 return out 36 return out
37 37
38 def get_meta(self): 38 def get_meta(self) -> Dict[str, Union[str, dict]]:
39 """ There is no way to escape the leading(s) dash(es) of the current 39 """ There is no way to escape the leading(s) dash(es) of the current
40 self.filename to prevent parameter injections, so we need to take care 40 self.filename to prevent parameter injections, so we need to take care
41 of this. 41 of this.
@@ -71,7 +71,7 @@ class PNGParser(_ImageParser):
71 except MemoryError: # pragma: no cover 71 except MemoryError: # pragma: no cover
72 raise ValueError 72 raise ValueError
73 73
74 def remove_all(self): 74 def remove_all(self) -> bool:
75 surface = cairo.ImageSurface.create_from_png(self.filename) 75 surface = cairo.ImageSurface.create_from_png(self.filename)
76 surface.write_to_png(self.output_filename) 76 surface.write_to_png(self.output_filename)
77 return True 77 return True
@@ -83,7 +83,12 @@ class GdkPixbufAbstractParser(_ImageParser):
83 """ 83 """
84 _type = '' 84 _type = ''
85 85
86 def remove_all(self): 86 def __init__(self, filename):
87 super().__init__(filename)
88 if imghdr.what(filename) != self._type: # better safe than sorry
89 raise ValueError
90
91 def remove_all(self) -> bool:
87 _, extension = os.path.splitext(self.filename) 92 _, extension = os.path.splitext(self.filename)
88 pixbuf = GdkPixbuf.Pixbuf.new_from_file(self.filename) 93 pixbuf = GdkPixbuf.Pixbuf.new_from_file(self.filename)
89 if extension.lower() == '.jpg': 94 if extension.lower() == '.jpg':
@@ -91,11 +96,6 @@ class GdkPixbufAbstractParser(_ImageParser):
91 pixbuf.savev(self.output_filename, extension[1:], [], []) 96 pixbuf.savev(self.output_filename, extension[1:], [], [])
92 return True 97 return True
93 98
94 def __init__(self, filename):
95 super().__init__(filename)
96 if imghdr.what(filename) != self._type: # better safe than sorry
97 raise ValueError
98
99 99
100class JPGParser(GdkPixbufAbstractParser): 100class JPGParser(GdkPixbufAbstractParser):
101 _type = 'jpeg' 101 _type = 'jpeg'
diff --git a/libmat2/office.py b/libmat2/office.py
index 32e7b75..c10664f 100644
--- a/libmat2/office.py
+++ b/libmat2/office.py
@@ -2,7 +2,7 @@ import logging
2import os 2import os
3import re 3import re
4import zipfile 4import zipfile
5from typing import Dict, Set, Pattern, Tuple 5from typing import Dict, Set, Pattern, Tuple, Union
6 6
7import xml.etree.ElementTree as ET # type: ignore 7import xml.etree.ElementTree as ET # type: ignore
8 8
@@ -296,7 +296,7 @@ class MSOfficeParser(ArchiveBasedAbstractParser):
296 296
297 return True 297 return True
298 298
299 def get_meta(self) -> Dict[str, str]: 299 def get_meta(self) -> Dict[str, Union[str, dict]]:
300 """ 300 """
301 Yes, I know that parsing xml with regexp ain't pretty, 301 Yes, I know that parsing xml with regexp ain't pretty,
302 be my guest and fix it if you want. 302 be my guest and fix it if you want.
@@ -381,7 +381,7 @@ class LibreOfficeParser(ArchiveBasedAbstractParser):
381 return False 381 return False
382 return True 382 return True
383 383
384 def get_meta(self) -> Dict[str, str]: 384 def get_meta(self) -> Dict[str, Union[str, dict]]:
385 """ 385 """
386 Yes, I know that parsing xml with regexp ain't pretty, 386 Yes, I know that parsing xml with regexp ain't pretty,
387 be my guest and fix it if you want. 387 be my guest and fix it if you want.
diff --git a/libmat2/pdf.py b/libmat2/pdf.py
index 140b4f4..17cd61e 100644
--- a/libmat2/pdf.py
+++ b/libmat2/pdf.py
@@ -7,6 +7,7 @@ import re
7import logging 7import logging
8import tempfile 8import tempfile
9import io 9import io
10from typing import Dict, Union
10from distutils.version import LooseVersion 11from distutils.version import LooseVersion
11 12
12import cairo 13import cairo
@@ -130,7 +131,7 @@ class PDFParser(abstract.AbstractParser):
130 metadata[key] = value 131 metadata[key] = value
131 return metadata 132 return metadata
132 133
133 def get_meta(self): 134 def get_meta(self) -> Dict[str, Union[str, dict]]:
134 """ Return a dict with all the meta of the file 135 """ Return a dict with all the meta of the file
135 """ 136 """
136 metadata = {} 137 metadata = {}
diff --git a/libmat2/torrent.py b/libmat2/torrent.py
index c56e971..4d6c1e0 100644
--- a/libmat2/torrent.py
+++ b/libmat2/torrent.py
@@ -14,7 +14,7 @@ class TorrentParser(abstract.AbstractParser):
14 if self.dict_repr is None: 14 if self.dict_repr is None:
15 raise ValueError 15 raise ValueError
16 16
17 def get_meta(self) -> Dict[str, str]: 17 def get_meta(self) -> Dict[str, Union[str, dict]]:
18 metadata = {} 18 metadata = {}
19 for key, value in self.dict_repr.items(): 19 for key, value in self.dict_repr.items():
20 if key not in self.whitelist: 20 if key not in self.whitelist: