Bump mypy typing coverage
This commit is contained in:
parent
b832a59414
commit
2ba38dd2a1
@ -8,6 +8,7 @@ from typing import Dict, Optional
|
||||
|
||||
# make pyflakes happy
|
||||
assert Dict
|
||||
assert Optional
|
||||
|
||||
# A set of extension that aren't supported, despite matching a supported mimetype
|
||||
UNSUPPORTED_EXTENSIONS = {
|
||||
@ -36,7 +37,7 @@ DEPENDENCIES = {
|
||||
'mutagen': 'Mutagen',
|
||||
}
|
||||
|
||||
def _get_exiftool_path() -> Optional[str]: # pragma: no cover
|
||||
def _get_exiftool_path() -> str: # pragma: no cover
|
||||
exiftool_path = '/usr/bin/exiftool'
|
||||
if os.path.isfile(exiftool_path):
|
||||
if os.access(exiftool_path, os.X_OK):
|
||||
@ -48,7 +49,7 @@ def _get_exiftool_path() -> Optional[str]: # pragma: no cover
|
||||
if os.access(exiftool_path, os.X_OK):
|
||||
return exiftool_path
|
||||
|
||||
return None
|
||||
raise ValueError
|
||||
|
||||
def check_dependencies() -> dict:
|
||||
ret = collections.defaultdict(bool) # type: Dict[str, bool]
|
||||
|
@ -1,6 +1,6 @@
|
||||
import abc
|
||||
import os
|
||||
from typing import Set, Dict
|
||||
from typing import Set, Dict, Union
|
||||
|
||||
assert Set # make pyflakes happy
|
||||
|
||||
@ -22,7 +22,7 @@ class AbstractParser(abc.ABC):
|
||||
self.lightweight_cleaning = False
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_meta(self) -> Dict[str, str]:
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
pass # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
|
@ -4,13 +4,14 @@ import tempfile
|
||||
import os
|
||||
import logging
|
||||
import shutil
|
||||
from typing import Dict, Set, Pattern
|
||||
from typing import Dict, Set, Pattern, Union
|
||||
|
||||
from . import abstract, UnknownMemberPolicy, parser_factory
|
||||
|
||||
# Make pyflakes happy
|
||||
assert Set
|
||||
assert Pattern
|
||||
assert Union
|
||||
|
||||
|
||||
class ArchiveBasedAbstractParser(abstract.AbstractParser):
|
||||
|
@ -2,6 +2,7 @@ import mimetypes
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from typing import Dict, Union
|
||||
|
||||
import mutagen
|
||||
|
||||
@ -16,13 +17,13 @@ class MutagenParser(abstract.AbstractParser):
|
||||
except mutagen.MutagenError:
|
||||
raise ValueError
|
||||
|
||||
def get_meta(self):
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
f = mutagen.File(self.filename)
|
||||
if f.tags:
|
||||
return {k:', '.join(v) for k, v in f.tags.items()}
|
||||
return {}
|
||||
|
||||
def remove_all(self):
|
||||
def remove_all(self) -> bool:
|
||||
shutil.copy(self.filename, self.output_filename)
|
||||
f = mutagen.File(self.output_filename)
|
||||
f.delete()
|
||||
@ -33,8 +34,8 @@ class MutagenParser(abstract.AbstractParser):
|
||||
class MP3Parser(MutagenParser):
|
||||
mimetypes = {'audio/mpeg', }
|
||||
|
||||
def get_meta(self):
|
||||
metadata = {}
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
metadata = {} # type: Dict[str, Union[str, dict]]
|
||||
meta = mutagen.File(self.filename).tags
|
||||
for key in meta:
|
||||
metadata[key.rstrip(' \t\r\n\0')] = ', '.join(map(str, meta[key].text))
|
||||
@ -48,7 +49,7 @@ class OGGParser(MutagenParser):
|
||||
class FLACParser(MutagenParser):
|
||||
mimetypes = {'audio/flac', 'audio/x-flac'}
|
||||
|
||||
def remove_all(self):
|
||||
def remove_all(self) -> bool:
|
||||
shutil.copy(self.filename, self.output_filename)
|
||||
f = mutagen.File(self.output_filename)
|
||||
f.clear_pictures()
|
||||
@ -56,16 +57,21 @@ class FLACParser(MutagenParser):
|
||||
f.save(deleteid3=True)
|
||||
return True
|
||||
|
||||
def get_meta(self):
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
meta = super().get_meta()
|
||||
for num, picture in enumerate(mutagen.File(self.filename).pictures):
|
||||
name = picture.desc if picture.desc else 'Cover %d' % num
|
||||
extension = mimetypes.guess_extension(picture.mime)
|
||||
if extension is None: # pragma: no cover
|
||||
meta[name] = 'harmful data'
|
||||
continue
|
||||
|
||||
_, fname = tempfile.mkstemp()
|
||||
fname = fname + extension
|
||||
with open(fname, 'wb') as f:
|
||||
f.write(picture.data)
|
||||
extension = mimetypes.guess_extension(picture.mime)
|
||||
shutil.move(fname, fname + extension)
|
||||
p, _ = parser_factory.get_parser(fname+extension)
|
||||
meta[name] = p.get_meta() if p else 'harmful data'
|
||||
os.remove(fname + extension)
|
||||
p, _ = parser_factory.get_parser(fname) # type: ignore
|
||||
# Mypy chokes on ternaries :/
|
||||
meta[name] = p.get_meta() if p else 'harmful data' # type: ignore
|
||||
os.remove(fname)
|
||||
return meta
|
||||
|
@ -1,5 +1,5 @@
|
||||
import shutil
|
||||
from typing import Dict
|
||||
from typing import Dict, Union
|
||||
from . import abstract
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ class HarmlessParser(abstract.AbstractParser):
|
||||
""" This is the parser for filetypes that can not contain metadata. """
|
||||
mimetypes = {'text/plain', 'image/x-ms-bmp'}
|
||||
|
||||
def get_meta(self) -> Dict[str, str]:
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
return dict()
|
||||
|
||||
def remove_all(self) -> bool:
|
||||
|
@ -5,7 +5,7 @@ import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import re
|
||||
from typing import Set
|
||||
from typing import Set, Dict, Union
|
||||
|
||||
import cairo
|
||||
|
||||
@ -25,7 +25,7 @@ class _ImageParser(abstract.AbstractParser):
|
||||
meta_whitelist = set() # type: Set[str]
|
||||
|
||||
@staticmethod
|
||||
def __handle_problematic_filename(filename: str, callback) -> str:
|
||||
def __handle_problematic_filename(filename: str, callback) -> bytes:
|
||||
""" This method takes a filename with a problematic name,
|
||||
and safely applies it a `callback`."""
|
||||
tmpdirname = tempfile.mkdtemp()
|
||||
@ -35,7 +35,7 @@ class _ImageParser(abstract.AbstractParser):
|
||||
shutil.rmtree(tmpdirname)
|
||||
return out
|
||||
|
||||
def get_meta(self):
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
""" There is no way to escape the leading(s) dash(es) of the current
|
||||
self.filename to prevent parameter injections, so we need to take care
|
||||
of this.
|
||||
@ -71,7 +71,7 @@ class PNGParser(_ImageParser):
|
||||
except MemoryError: # pragma: no cover
|
||||
raise ValueError
|
||||
|
||||
def remove_all(self):
|
||||
def remove_all(self) -> bool:
|
||||
surface = cairo.ImageSurface.create_from_png(self.filename)
|
||||
surface.write_to_png(self.output_filename)
|
||||
return True
|
||||
@ -83,7 +83,12 @@ class GdkPixbufAbstractParser(_ImageParser):
|
||||
"""
|
||||
_type = ''
|
||||
|
||||
def remove_all(self):
|
||||
def __init__(self, filename):
|
||||
super().__init__(filename)
|
||||
if imghdr.what(filename) != self._type: # better safe than sorry
|
||||
raise ValueError
|
||||
|
||||
def remove_all(self) -> bool:
|
||||
_, extension = os.path.splitext(self.filename)
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file(self.filename)
|
||||
if extension.lower() == '.jpg':
|
||||
@ -91,11 +96,6 @@ class GdkPixbufAbstractParser(_ImageParser):
|
||||
pixbuf.savev(self.output_filename, extension[1:], [], [])
|
||||
return True
|
||||
|
||||
def __init__(self, filename):
|
||||
super().__init__(filename)
|
||||
if imghdr.what(filename) != self._type: # better safe than sorry
|
||||
raise ValueError
|
||||
|
||||
|
||||
class JPGParser(GdkPixbufAbstractParser):
|
||||
_type = 'jpeg'
|
||||
|
@ -2,7 +2,7 @@ import logging
|
||||
import os
|
||||
import re
|
||||
import zipfile
|
||||
from typing import Dict, Set, Pattern, Tuple
|
||||
from typing import Dict, Set, Pattern, Tuple, Union
|
||||
|
||||
import xml.etree.ElementTree as ET # type: ignore
|
||||
|
||||
@ -296,7 +296,7 @@ class MSOfficeParser(ArchiveBasedAbstractParser):
|
||||
|
||||
return True
|
||||
|
||||
def get_meta(self) -> Dict[str, str]:
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
"""
|
||||
Yes, I know that parsing xml with regexp ain't pretty,
|
||||
be my guest and fix it if you want.
|
||||
@ -381,7 +381,7 @@ class LibreOfficeParser(ArchiveBasedAbstractParser):
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_meta(self) -> Dict[str, str]:
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
"""
|
||||
Yes, I know that parsing xml with regexp ain't pretty,
|
||||
be my guest and fix it if you want.
|
||||
|
@ -7,6 +7,7 @@ import re
|
||||
import logging
|
||||
import tempfile
|
||||
import io
|
||||
from typing import Dict, Union
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
import cairo
|
||||
@ -130,7 +131,7 @@ class PDFParser(abstract.AbstractParser):
|
||||
metadata[key] = value
|
||||
return metadata
|
||||
|
||||
def get_meta(self):
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
""" Return a dict with all the meta of the file
|
||||
"""
|
||||
metadata = {}
|
||||
|
@ -14,7 +14,7 @@ class TorrentParser(abstract.AbstractParser):
|
||||
if self.dict_repr is None:
|
||||
raise ValueError
|
||||
|
||||
def get_meta(self) -> Dict[str, str]:
|
||||
def get_meta(self) -> Dict[str, Union[str, dict]]:
|
||||
metadata = {}
|
||||
for key, value in self.dict_repr.items():
|
||||
if key not in self.whitelist:
|
||||
|
18
mat2
18
mat2
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
from typing import Tuple, Generator, List
|
||||
from typing import Tuple, Generator, List, Union
|
||||
import sys
|
||||
import mimetypes
|
||||
import argparse
|
||||
@ -18,6 +18,7 @@ __version__ = '0.4.0'
|
||||
|
||||
# Make pyflakes happy
|
||||
assert Tuple
|
||||
assert Union
|
||||
|
||||
|
||||
def __check_file(filename: str, mode: int=os.R_OK) -> bool:
|
||||
@ -98,12 +99,12 @@ def clean_meta(filename: str, is_lightweight: bool, policy: UnknownMemberPolicy)
|
||||
return p.remove_all()
|
||||
|
||||
|
||||
def show_parsers():
|
||||
def show_parsers() -> bool:
|
||||
print('[+] Supported formats:')
|
||||
formats = set()
|
||||
for parser in parser_factory._get_parsers():
|
||||
formats = set() # Set[str]
|
||||
for parser in parser_factory._get_parsers(): # type: ignore
|
||||
for mtype in parser.mimetypes:
|
||||
extensions = set()
|
||||
extensions = set() # Set[str]
|
||||
for extension in mimetypes.guess_all_extensions(mtype):
|
||||
if extension not in UNSUPPORTED_EXTENSIONS:
|
||||
extensions.add(extension)
|
||||
@ -113,6 +114,7 @@ def show_parsers():
|
||||
continue
|
||||
formats.add(' - %s (%s)' % (mtype, ', '.join(extensions)))
|
||||
print('\n'.join(sorted(formats)))
|
||||
return True
|
||||
|
||||
|
||||
def __get_files_recursively(files: List[str]) -> Generator[str, None, None]:
|
||||
@ -126,7 +128,7 @@ def __get_files_recursively(files: List[str]) -> Generator[str, None, None]:
|
||||
elif __check_file(f):
|
||||
yield f
|
||||
|
||||
def main():
|
||||
def main() -> int:
|
||||
arg_parser = create_arg_parser()
|
||||
args = arg_parser.parse_args()
|
||||
|
||||
@ -135,13 +137,13 @@ def main():
|
||||
|
||||
if not args.files:
|
||||
if args.list:
|
||||
show_parsers()
|
||||
return show_parsers()
|
||||
elif args.check_dependencies:
|
||||
print("Dependencies required for MAT2 %s:" % __version__)
|
||||
for key, value in sorted(check_dependencies().items()):
|
||||
print('- %s: %s' % (key, 'yes' if value else 'no'))
|
||||
else:
|
||||
return arg_parser.print_help()
|
||||
arg_parser.print_help()
|
||||
return 0
|
||||
|
||||
elif args.show:
|
||||
|
Loading…
Reference in New Issue
Block a user