From d1b8155e33e3ddbab4f2e4567fa42aa706d72225 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Thu, 20 Feb 2020 23:35:53 +0100 Subject: [PATCH] Improvements4 (#200) * doc strings according to PEP * skipped tests marked properly * refactored CLI * added autocompletion * cleanup * switch github actions from checkout@v1 to checkout@v2 * fixed codecov name in github actions --- .github/workflows/pythonpackage.yml | 4 +- .github/workflows/pythonpublish.yml | 4 +- HISTORY.md | 4 + nichtparasoup/__main__.py | 4 +- nichtparasoup/_internals/__init__.py | 11 +- nichtparasoup/cli/__init__.py | 4 + .../{cmdline/__init__.py => cli/commands.py} | 42 +++--- nichtparasoup/cli/main.py | 24 ++++ nichtparasoup/cli/parser.py | 120 ++++++++++++++++++ nichtparasoup/cmdline/argparse.py | 85 ------------- nichtparasoup/core/image.py | 3 +- nichtparasoup/core/imagecrawler.py | 21 +-- nichtparasoup/core/server.py | 13 +- nichtparasoup/imagecrawler/instagram.py | 3 +- nichtparasoup/testing/__init__.py | 4 +- nichtparasoup/testing/imagecrawler.py | 3 +- setup.py | 3 +- .../test_cli/test_commands.py | 60 +++++++++ .../test_cli/test_main.py | 14 ++ .../test_cli/test_parser.py | 18 +++ .../test_cmdline/test_argparse.py | 14 -- .../test_cmdline/test_commands.py | 49 ------- .../test_cmdline/test_main.py | 7 - .../test_core/mockable_imagecrawler.py | 7 +- .../test_core/test_crawler.py | 18 +-- .../test_knownimagecrawlers.py | 3 +- .../test_imagecrawler/test_reddit.py | 3 +- .../test_webserver/test_webserver.py | 3 +- 28 files changed, 321 insertions(+), 227 deletions(-) create mode 100644 nichtparasoup/cli/__init__.py rename nichtparasoup/{cmdline/__init__.py => cli/commands.py} (83%) create mode 100644 nichtparasoup/cli/main.py create mode 100644 nichtparasoup/cli/parser.py delete mode 100644 nichtparasoup/cmdline/argparse.py create mode 100644 tests/test_10_nichtparasoup/test_cli/test_commands.py create mode 100644 tests/test_10_nichtparasoup/test_cli/test_main.py create mode 100644 tests/test_10_nichtparasoup/test_cli/test_parser.py delete mode 100644 tests/test_10_nichtparasoup/test_cmdline/test_argparse.py delete mode 100644 tests/test_10_nichtparasoup/test_cmdline/test_commands.py delete mode 100644 tests/test_10_nichtparasoup/test_cmdline/test_main.py diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 8290dcd8..59996fe4 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Fetch Code # see https://github.com/actions/checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set up Python ${{ matrix.pyhon_version }} # see https://github.com/actions/setup-python uses: actions/setup-python@v1 @@ -42,5 +42,5 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.xml flags: tests - name: od:${{ matrix.os }} py:${{ matrix.pyhon }} + name: "os:${{ matrix.os }} py:${{ matrix.pyhon }}" yml: ./codecov.yml diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index a42b8af2..7a0ab37b 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Fetch Code # see https://github.com/actions/checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set up Python # see https://github.com/actions/setup-python uses: actions/setup-python@v1 @@ -37,7 +37,7 @@ jobs: steps: - name: Fetch Code # see https://github.com/actions/checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Set up Python # see https://github.com/actions/setup-python uses: actions/setup-python@v1 diff --git a/HISTORY.md b/HISTORY.md index f810f9cc..ce5f9e55 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -12,6 +12,10 @@ * fixed issue [#187](https://github.com/k4cg/nichtparasoup/issues/187). * pinned test dependencies to greater/equal current latest minor version. +### Added + +* commandline autocompletion via [`argcomplete`](https://pypi.org/project/argcomplete/). + ## 2.3.1 diff --git a/nichtparasoup/__main__.py b/nichtparasoup/__main__.py index 588dadeb..7741326a 100644 --- a/nichtparasoup/__main__.py +++ b/nichtparasoup/__main__.py @@ -1,5 +1,5 @@ import sys -from nichtparasoup.cmdline import main +from nichtparasoup.cli.main import main as _main -sys.exit(main()) +sys.exit(_main()) diff --git a/nichtparasoup/_internals/__init__.py b/nichtparasoup/_internals/__init__.py index 8cdc130e..85616598 100644 --- a/nichtparasoup/_internals/__init__.py +++ b/nichtparasoup/_internals/__init__.py @@ -1,7 +1,8 @@ __all__ = ['_logger', '_log', '_message', '_message_exception', '_confirm'] + """ -yes, everything is underscored. -its internal foo that is not for public use. +Yes, everything is underscored. +Its internal foo that is not for public use. """ import logging @@ -30,6 +31,12 @@ def _log(level: _LOG_LEVEL, message: str, *args: Any, **kwargs: Any) -> None: getattr(_logger, level)(message.rstrip(), *args, **kwargs) +def _logging_init(level: int) -> None: # pragma: no cover + if not logging.root.handlers: + logging.root.setLevel(level) + logging.root.addHandler(logging.StreamHandler()) + + def _message(message: str, color: Optional[str] = None, file: Optional[TextIO] = None) -> None: from sys import stdout newline = '\r\n' diff --git a/nichtparasoup/cli/__init__.py b/nichtparasoup/cli/__init__.py new file mode 100644 index 00000000..13d491a1 --- /dev/null +++ b/nichtparasoup/cli/__init__.py @@ -0,0 +1,4 @@ +"""Subpackage containing all of nichtparasoup's command line interface related code +""" + +# This file intentionally does not import submodules diff --git a/nichtparasoup/cmdline/__init__.py b/nichtparasoup/cli/commands.py similarity index 83% rename from nichtparasoup/cmdline/__init__.py rename to nichtparasoup/cli/commands.py index 3d79c081..ba5c9f17 100644 --- a/nichtparasoup/cmdline/__init__.py +++ b/nichtparasoup/cli/commands.py @@ -1,20 +1,15 @@ import logging -from typing import Any, List, Optional +from typing import Any, Optional from nichtparasoup._internals import _message, _message_exception -def _logging_init(level: int) -> None: # pragma: no cover - if not logging.root.handlers: - logging.root.setLevel(level) - logging.root.addHandler(logging.StreamHandler()) - - class Commands(object): @staticmethod def run(config_file: Optional[str] = None) -> int: from os.path import abspath + from nichtparasoup._internals import _logging_init from nichtparasoup.config import get_config, get_imagecrawler from nichtparasoup.core import NPCore from nichtparasoup.core.server import Server as ImageServer @@ -35,7 +30,12 @@ def run(config_file: Optional[str] = None) -> int: return 1 @classmethod - def config(cls, action: str, config_file: str) -> int: + def config(cls, **actions: Any) -> int: + active_actions = dict((k, v) for k, v in actions.items() if v) + if len(active_actions) != 1: + _message_exception(ValueError('exactly one action required')) + return 255 + action, config_file = active_actions.popitem() return dict( check=cls.config_check_file, dump=cls.config_dump_file, @@ -44,10 +44,10 @@ def config(cls, action: str, config_file: str) -> int: @staticmethod def config_dump_file(config_file: str) -> int: from os.path import abspath, isfile + from nichtparasoup._internals import _confirm from nichtparasoup.config import dump_defaults config_file = abspath(config_file) if isfile(config_file): - from nichtparasoup._internals import _confirm overwrite = _confirm('File already exists, overwrite?') if overwrite is not True: _message('Abort.') @@ -80,20 +80,20 @@ def info(cls, **actions: Any) -> int: _message_exception(ValueError('exactly one action required')) return 255 action, action_value = active_actions.popitem() - return dict( + return dict( # type: ignore version=cls.info_version, imagecrawler_list=cls.info_imagecrawler_list, imagecrawler_desc=cls.info_imagecrawler_desc, )[action](action_value) @staticmethod - def info_version(_: Any) -> int: + def info_version(_: Optional[Any] = None) -> int: from nichtparasoup import VERSION _message(VERSION) return 0 @staticmethod - def info_imagecrawler_list(_: Any) -> int: + def info_imagecrawler_list(_: Optional[Any] = None) -> int: from nichtparasoup.imagecrawler import get_imagecrawlers imagecrawlers = get_imagecrawlers().names() if not imagecrawlers: @@ -133,12 +133,12 @@ def info_imagecrawler_desc(imagecrawler: str) -> int: ])) return 0 - -def main(args: Optional[List[str]] = None) -> int: - from nichtparasoup.cmdline.argparse import parser as argparser - options = dict(argparser.parse_args(args=args).__dict__) - if options.pop('debug', False): - _logging_init(logging.DEBUG) - _message('DEBUG ENABLED :)', 'cyan') - command = options.pop('command') - return getattr(Commands, command)(**options) # type: ignore + @staticmethod + def completion(shell: str) -> int: + from sys import stdout + from argcomplete import shellcode # type: ignore + stdout.write(shellcode( + ['nichtparasoup'], shell=shell, + use_defaults=True, complete_arguments=None, + )) + return 0 diff --git a/nichtparasoup/cli/main.py b/nichtparasoup/cli/main.py new file mode 100644 index 00000000..15bcccc1 --- /dev/null +++ b/nichtparasoup/cli/main.py @@ -0,0 +1,24 @@ +# PYTHON_ARGCOMPLETE_OK + +__all__ = ["main"] + +import logging +from typing import List, Optional + +from argcomplete import autocomplete # type: ignore + +from nichtparasoup._internals import _logging_init, _message +from nichtparasoup.cli.commands import Commands +from nichtparasoup.cli.parser import create_parser + + +def main(args: Optional[List[str]] = None) -> int: # pragma: no cover + parser = create_parser() + autocomplete(parser, always_complete_options='long') + options = dict(parser.parse_args(args=args).__dict__) + del parser + if options.pop('debug', False): + _logging_init(logging.DEBUG) + _message('DEBUG ENABLED :)', 'cyan') + command = options.pop('command') + return getattr(Commands, command)(**options) # type: ignore diff --git a/nichtparasoup/cli/parser.py b/nichtparasoup/cli/parser.py new file mode 100644 index 00000000..6012c2b3 --- /dev/null +++ b/nichtparasoup/cli/parser.py @@ -0,0 +1,120 @@ +__all__ = ["create_parser"] + +from argparse import ArgumentParser +from typing import Any, Set + +from argcomplete import FilesCompleter # type: ignore + +from nichtparasoup.imagecrawler import get_imagecrawlers + + +def imagecrawler_completion(*args: Any, **kwargs: Any) -> Set[str]: + return set(get_imagecrawlers().names()) + + +yaml_file_completion = FilesCompleter('yaml', 'yml') + + +def create_parser() -> ArgumentParser: # pragma: no cover + # used `__tmp_action` several times, to omit type-checkers warning ala 'Action has no attribute "completer"' + + parser = ArgumentParser( + add_help=True, + allow_abbrev=False, + ) + + parser.add_argument( + '--debug', + help='Enable debug output.', + action='store_true', dest="debug", + ) + + commands = parser.add_subparsers( + title='Commands', + metavar='', + dest='command', + ) + commands.required = True + + command_run = commands.add_parser( + 'run', + help='run a server', + description='Start a web-server to display random images.', + add_help=True, + allow_abbrev=False, + ) + __tmp_action = command_run.add_argument( + '-c', '--use-config', + help='Use a YAML config file instead of the defaults.', + metavar='', + action='store', dest="config_file", type=str, + ) + __tmp_action.completer = yaml_file_completion # type: ignore + del __tmp_action + + command_config = commands.add_parser( + 'config', + description='Get config related things done.', + help='Config related functions.', + add_help=True, + allow_abbrev=False, + ) + command_config_switches = command_config.add_mutually_exclusive_group(required=True) + __tmp_action = command_config_switches.add_argument( + '--check', + help='Validate and probe a YAML config file;', + metavar='', + action='store', dest='check', type=str, + ) + __tmp_action.completer = yaml_file_completion # type: ignore + del __tmp_action + command_config_switches.add_argument( + '--dump', + help='Dump YAML config into a file;', + metavar='', + action='store', dest='dump', type=str, + ) + + command_info = commands.add_parser( + 'info', + description='Get info for several topics.', + help='Get info for several topics.', + add_help=True, + allow_abbrev=False, + ) + command_info_switches = command_info.add_mutually_exclusive_group(required=True) + command_info_switches.add_argument( + '--imagecrawler-list', + help='List available image crawler types.', + action='store_true', dest='imagecrawler_list', + ) + __tmp_action = command_info_switches.add_argument( + '--imagecrawler-desc', + help='Describe an image crawler type and its config.', + metavar='', + action='store', dest='imagecrawler_desc', type=str, + ) + __tmp_action.completer = imagecrawler_completion # type: ignore + del __tmp_action + command_info_switches.add_argument( + '--version', + help="Show program's version number.", + action='store_true', dest='version', + ) + + command_completion = commands.add_parser( + 'completion', + description='Helper command used for command completion.', + epilog='Autocompletion is powered by https://pypi.org/project/argcomplete/', + help='Helper command to be used for command completion.', + add_help=True, + allow_abbrev=False, + ) + command_completion.add_argument( + '-s', '--shell', + help='Emit completion code for the specified shell.', + action='store', dest='shell', type=str, required=True, + choices=('bash', 'tcsh', 'fish'), + ) + + return parser diff --git a/nichtparasoup/cmdline/argparse.py b/nichtparasoup/cmdline/argparse.py deleted file mode 100644 index 398b1151..00000000 --- a/nichtparasoup/cmdline/argparse.py +++ /dev/null @@ -1,85 +0,0 @@ -# pragma: no cover - -__all__ = ["parser"] - -from argparse import ArgumentParser - -parser = ArgumentParser( - add_help=True, - allow_abbrev=False, -) - -commands = parser.add_subparsers( - title='Commands', - metavar='', - dest='command', -) -commands.required = True - -parser.add_argument( - '--debug', - help='enable debug output', - action='store_true', dest="debug", -) - -command_run = commands.add_parser( - 'run', - help='run a server', - description='start a webserver to display random images', - add_help=True, - allow_abbrev=False, -) -command_run.add_argument( - '-c', '--use-config', - help='use a YAML config file instead of the defaults', - metavar='', - action='store', dest="config_file", type=str, -) - -command_config = commands.add_parser( - 'config', - description='Get config related things done', - help='config related functions', - add_help=True, - allow_abbrev=False, -) -command_config_actions = command_config.add_mutually_exclusive_group(required=True) -command_config_actions.add_argument( - '--check', - help='validate and probe a YAML config file', - action='store_const', dest='action', const='check', -) -command_config_actions.add_argument( - '--dump', - help='dump YAML config into a file', - action='store_const', dest='action', const='dump', -) -command_config.add_argument( - metavar='', - action='store', dest='config_file', type=str, -) - -command_info = commands.add_parser( - 'info', - description='Get info for several topics', - help='get info for several topics', - add_help=True, - allow_abbrev=False, -) -command_info_actions = command_info.add_mutually_exclusive_group(required=True) -command_info_actions.add_argument( - '--imagecrawler-list', - help='list available image crawler types', - action='store_true', dest='imagecrawler_list', -) -command_info_actions.add_argument( - '--imagecrawler-desc', - help='describe an image crawler type and its config', - metavar='', - action='store', dest='imagecrawler_desc', type=str, -) -command_info_actions.add_argument( - '--version', - help="show program's version number", - action='store_true', dest='version', -) diff --git a/nichtparasoup/core/image.py b/nichtparasoup/core/image.py index 33ad3209..31b4b57e 100644 --- a/nichtparasoup/core/image.py +++ b/nichtparasoup/core/image.py @@ -9,8 +9,7 @@ class Image(object): - """ - Describe an image + """Describe an image `uri` The absolute URI of the image. This basically identifies the Image and makes it unique. diff --git a/nichtparasoup/core/imagecrawler.py b/nichtparasoup/core/imagecrawler.py index d321297a..a11292b6 100644 --- a/nichtparasoup/core/imagecrawler.py +++ b/nichtparasoup/core/imagecrawler.py @@ -16,8 +16,7 @@ class ImageCrawlerInfo(object): - """ - ImageCrawler's Info. + """ImageCrawler's Info. .. seealso:: :method:`BaseImageCrawler.info()` @@ -64,11 +63,9 @@ def __eq__(self, other: Any) -> bool: return False def get_config(self) -> ImageCrawlerConfig: - """ - Get all *public* information from the config + """Get all *public* information from the config For internal access to the config using `self._config` is encouraged - """ return ImageCrawlerConfig({ k: v @@ -99,8 +96,7 @@ def crawl(self) -> ImageCollection: # pragma: no cover @classmethod @abstractmethod def info(cls) -> ImageCrawlerInfo: # pragma: no cover - """ - Get info of the crawler + """Get info of the crawler example implementation: return ImageCrawlerInfo( @@ -117,15 +113,13 @@ def info(cls) -> ImageCrawlerInfo: # pragma: no cover ), icon_url='https://my.imagesource.net/favicon.png' ) - """ raise NotImplementedError() @classmethod @abstractmethod def check_config(cls, config: Dict[Any, Any]) -> ImageCrawlerConfig: # pragma: no cover - """ - This function is intended to check if a config is valid and to strip unused config. + """This function is intended to check if a config is valid and to strip unused config. When implementing: Check if any config is viable. if not raise ValueError or TypeError or KeyError @@ -138,21 +132,18 @@ def check_config(cls, config: Dict[Any, Any]) -> ImageCrawlerConfig: # pragma: raise TypeError("height {} is not int".format(height)) if height <= 0: raise ValueError("height {} <= 0".format(width)) - """ raise NotImplementedError() @abstractmethod def _reset(self) -> None: # pragma: no cover - """ - This function is intended to reset the crawler to restart at front + """This function is intended to reset the crawler to restart at front """ raise NotImplementedError() @abstractmethod def _crawl(self) -> ImageCollection: # pragma: no cover - """ - This function is intended to find and fetch ImageURIs + """This function is intended to find and fetch ImageURIs """ raise NotImplementedError() diff --git a/nichtparasoup/core/server.py b/nichtparasoup/core/server.py index d9f3338f..169c9fa0 100644 --- a/nichtparasoup/core/server.py +++ b/nichtparasoup/core/server.py @@ -15,9 +15,10 @@ class Server(object): """ - this class is intended to be thread save. - this class intended to be a stable interface. - its public methods return base types only. + + This class is intended to be thread save. + This class intended to be a stable interface. + Its public methods return base types only. """ def __init__(self, core: NPCore, crawler_upkeep: int = 30, @@ -116,9 +117,9 @@ def stop(self) -> None: class ServerStatus(ABC): """ - this class intended to be a stable interface. - all public methods are like this: Callable[[Server], Union[List[SomeBaseType], Dict[str, SomeBaseType]]] - all public methods must be associated with stat(u)s! + This class intended to be a stable interface. + All public methods are like this: Callable[[Server], Union[List[SomeBaseType], Dict[str, SomeBaseType]]] + All public methods must be associated with stat(u)s! """ @staticmethod diff --git a/nichtparasoup/imagecrawler/instagram.py b/nichtparasoup/imagecrawler/instagram.py index 2d8fb23b..3cb5da36 100644 --- a/nichtparasoup/imagecrawler/instagram.py +++ b/nichtparasoup/imagecrawler/instagram.py @@ -168,8 +168,7 @@ def _query(self, uri: str) -> Dict[str, Any]: @classmethod @abstractmethod def _get_media_from_query_response(cls, response: Dict[str, Any]) -> Dict[str, Any]: # pragma: no cover - """ - get the path for media edges in query response + """Get the path for media edges in query response example implementation: return response['data']['']['edge__media'] diff --git a/nichtparasoup/testing/__init__.py b/nichtparasoup/testing/__init__.py index 0e855c8b..a3528ff4 100644 --- a/nichtparasoup/testing/__init__.py +++ b/nichtparasoup/testing/__init__.py @@ -1,4 +1,4 @@ +"""Subpackage containing all of nichtparasoup's testing related code """ -in this package you will find stuff that helps with testing -""" +# This file intentionally does not import submodules diff --git a/nichtparasoup/testing/imagecrawler.py b/nichtparasoup/testing/imagecrawler.py index bdca2c8a..e8927345 100644 --- a/nichtparasoup/testing/imagecrawler.py +++ b/nichtparasoup/testing/imagecrawler.py @@ -103,8 +103,7 @@ def ic_name(self) -> str: # pragma: no cover @property @abstractmethod def ic_class(self) -> Type[BaseImageCrawler]: # pragma: no cover - """ - the class of your ImageCrawler. + """the class of your ImageCrawler. Example implementation: return MyImageCrawler diff --git a/setup.py b/setup.py index d594a7e9..c5ac739b 100755 --- a/setup.py +++ b/setup.py @@ -45,6 +45,7 @@ 'werkzeug>=1.0', # for `webserver` 'mako>=1.1', # for `webserver`'s templates 'setuptools>=40.0', # for imagecrawler-plugin-architecture + 'argcomplete>=1.11', # for cli autocompletion ] # What packages are optional? @@ -109,7 +110,7 @@ packages=find_packages(exclude=['tests', '*.tests', '*.tests.*', 'tests.*', 'examples']), entry_points=dict( console_scripts=[ - 'nichtparasoup = nichtparasoup.cmdline:main', + 'nichtparasoup = nichtparasoup.cli.main:main', ], ), setup_requires=['setuptools', 'setuptools_scm>=3.3.3'], diff --git a/tests/test_10_nichtparasoup/test_cli/test_commands.py b/tests/test_10_nichtparasoup/test_cli/test_commands.py new file mode 100644 index 00000000..643314f1 --- /dev/null +++ b/tests/test_10_nichtparasoup/test_cli/test_commands.py @@ -0,0 +1,60 @@ +import unittest + +from nichtparasoup.cli.commands import Commands + + +class CommandsRunTest(unittest.TestCase): + + @unittest.skip("TODO: write the test") + def test_(self) -> None: + raise NotImplementedError() + + +class CommandsConfigTest(unittest.TestCase): + + @unittest.skip("TODO: write the test") + def test_(self) -> None: + raise NotImplementedError() + + +class CommandsConfigDumpFileTest(unittest.TestCase): + + @unittest.skip("TODO: write the test") + def test_(self) -> None: + raise NotImplementedError() + + +class CommandsConfigCheckFileTest(unittest.TestCase): + + @unittest.skip("TODO: write the test") + def test_(self) -> None: + raise NotImplementedError() + + +class CommandsInfoTest(unittest.TestCase): + + @unittest.skip("TODO: write the test") + def test_(self) -> None: + raise NotImplementedError() + + +class CommandsInfoVersionTest(unittest.TestCase): + + def test_version(self) -> None: + # TODO catch stdout and check against current nichtparasoup.VERSION + ret = Commands.info_version() + self.assertEqual(0, ret) + + +class CommandsInfoImagecrawlerListTest(unittest.TestCase): + + @unittest.skip("TODO: write the test") + def test_(self) -> None: + raise NotImplementedError() + + +class CommandsInfoImagecrawlerDescTest(unittest.TestCase): + + @unittest.skip("TODO: write the test") + def test_(self) -> None: + raise NotImplementedError() diff --git a/tests/test_10_nichtparasoup/test_cli/test_main.py b/tests/test_10_nichtparasoup/test_cli/test_main.py new file mode 100644 index 00000000..aac656c0 --- /dev/null +++ b/tests/test_10_nichtparasoup/test_cli/test_main.py @@ -0,0 +1,14 @@ +import unittest + +from nichtparasoup.cli.main import main as main_ + + +class CommandsRunTest(unittest.TestCase): + """Current implementation is just a preparation for later. + """ + + @unittest.skip("nothing to test, yet") + def test_nothing(self) -> None: + """Current implementation is a placeholder, so the imported main_ stays active. + """ + main_() diff --git a/tests/test_10_nichtparasoup/test_cli/test_parser.py b/tests/test_10_nichtparasoup/test_cli/test_parser.py new file mode 100644 index 00000000..de1459f5 --- /dev/null +++ b/tests/test_10_nichtparasoup/test_cli/test_parser.py @@ -0,0 +1,18 @@ +import unittest + +from nichtparasoup.cli.parser import create_parser + + +class CommandsRunTest(unittest.TestCase): + """Current implementation is just a preparation for later. + """ + + def setUp(self) -> None: + self.parser = create_parser() + + def tearDown(self) -> None: + del self.parser + + @unittest.skip("nothing to test, yet") + def test_nothing(self) -> None: + raise NotImplementedError() diff --git a/tests/test_10_nichtparasoup/test_cmdline/test_argparse.py b/tests/test_10_nichtparasoup/test_cmdline/test_argparse.py deleted file mode 100644 index c7fc9119..00000000 --- a/tests/test_10_nichtparasoup/test_cmdline/test_argparse.py +++ /dev/null @@ -1,14 +0,0 @@ -import unittest - - -class ArgParserTest(unittest.TestCase): - - def setUp(self) -> None: - from nichtparasoup.cmdline.argparse import parser - self.parser = parser - - def tearDown(self) -> None: - del self.parser - - def test_parser(self) -> None: - self.skipTest("TODO: write the test") # TODO: write the test diff --git a/tests/test_10_nichtparasoup/test_cmdline/test_commands.py b/tests/test_10_nichtparasoup/test_cmdline/test_commands.py deleted file mode 100644 index 9e70e8bb..00000000 --- a/tests/test_10_nichtparasoup/test_cmdline/test_commands.py +++ /dev/null @@ -1,49 +0,0 @@ -import unittest - - -class CommandsRunTest(unittest.TestCase): - - def test_(self) -> None: - self.skipTest('TODO') - - -class CommandsConfigTest(unittest.TestCase): - - def test_(self) -> None: - self.skipTest('TODO') - - -class CommandsConfigDumpFileTest(unittest.TestCase): - - def test_(self) -> None: - self.skipTest('TODO') - - -class CommandsConfigCheckFileTest(unittest.TestCase): - - def test_(self) -> None: - self.skipTest('TODO') - - -class CommandsInfoTest(unittest.TestCase): - - def test_(self) -> None: - self.skipTest('TODO') - - -class CommandsInfoVersionTest(unittest.TestCase): - - def test_(self) -> None: - self.skipTest('TODO') - - -class CommandsInfoImagecrawlerListTest(unittest.TestCase): - - def test_(self) -> None: - self.skipTest('TODO') - - -class CommandsInfoImagecrawlerDescTest(unittest.TestCase): - - def test_(self) -> None: - self.skipTest('TODO') diff --git a/tests/test_10_nichtparasoup/test_cmdline/test_main.py b/tests/test_10_nichtparasoup/test_cmdline/test_main.py deleted file mode 100644 index cf1ccbf0..00000000 --- a/tests/test_10_nichtparasoup/test_cmdline/test_main.py +++ /dev/null @@ -1,7 +0,0 @@ -import unittest - - -class MainTest(unittest.TestCase): - - def test_main(self) -> None: - self.skipTest('TODO') diff --git a/tests/test_10_nichtparasoup/test_core/mockable_imagecrawler.py b/tests/test_10_nichtparasoup/test_core/mockable_imagecrawler.py index 94971c1a..742459df 100644 --- a/tests/test_10_nichtparasoup/test_core/mockable_imagecrawler.py +++ b/tests/test_10_nichtparasoup/test_core/mockable_imagecrawler.py @@ -7,7 +7,8 @@ class MockableImageCrawler(BaseImageCrawler): - """ imagecrawler that does nothing. use it for mocking ... """ + """An imagecrawler that does nothing. use it for mocking ... + """ @classmethod def info(cls) -> ImageCrawlerInfo: @@ -28,5 +29,7 @@ def _crawl(self) -> ImageCollection: class YetAnotherImageCrawler(MockableImageCrawler): - """ another implementation, to see if type matters """ + """ + another implementation, to see if type matters + """ pass diff --git a/tests/test_10_nichtparasoup/test_core/test_crawler.py b/tests/test_10_nichtparasoup/test_core/test_crawler.py index 2b6e57b9..b5bb0ced 100644 --- a/tests/test_10_nichtparasoup/test_core/test_crawler.py +++ b/tests/test_10_nichtparasoup/test_core/test_crawler.py @@ -26,8 +26,7 @@ def _f(_: Image) -> None: class CrawlerIsImageAddableTestCase(unittest.TestCase): - """ - test if the weakref is working as expected + """Test if the weakref is working as expected """ def setUp(self) -> None: @@ -79,7 +78,8 @@ def test_object_bound_method_deleted(self) -> None: self.assertIsNone(self.crawler.get_is_image_addable()) def test_function(self) -> None: - """ Remember: FunctionType is LambdaType """ + """Remember: FunctionType is LambdaType + """ # assert with self.assertRaises(Exception): # currently not supporting `function`. write the test, when writing it is supported @@ -87,8 +87,7 @@ def test_function(self) -> None: class CrawlerImageAddedTestCase(unittest.TestCase): - """ - test if the weakref is working as expected + """Test if the weakref is working as expected """ def setUp(self) -> None: @@ -140,7 +139,8 @@ def test_object_bound_method_deleted(self) -> None: self.assertIsNone(self.crawler.get_image_added()) def test_function(self) -> None: - """ Remember: FunctionType is LambdaType """ + """Remember: FunctionType is LambdaType + """ # assert with self.assertRaises(Exception): # currently not supporting `function`. write the test, when writing it is supported @@ -214,8 +214,10 @@ def on_get_image_added(image: Image) -> bool: class ServerRefillTest(unittest.TestCase): + @unittest.skip("TODO: write the test - use Random3Crawler") def test_fill_up_to(self) -> None: - self.skipTest("write the test - use Random3Crawler") + raise NotImplementedError() + @unittest.skip("TODO: write the test - use NullCrawler") def test_refill_null_crawler(self) -> None: - self.skipTest("write the test - use NullCrawler") + raise NotImplementedError() diff --git a/tests/test_10_nichtparasoup/test_imagecrawler/test_knownimagecrawlers.py b/tests/test_10_nichtparasoup/test_imagecrawler/test_knownimagecrawlers.py index 799fc2fe..b63b7386 100644 --- a/tests/test_10_nichtparasoup/test_imagecrawler/test_knownimagecrawlers.py +++ b/tests/test_10_nichtparasoup/test_imagecrawler/test_knownimagecrawlers.py @@ -195,7 +195,8 @@ def test_success(self) -> None: class KnownImageCrawlersBuiltinsTest(unittest.TestCase): def test_builtins(self) -> None: - """ test each builtin for the usual plugin needs """ + """Test each builtin for the usual plugin needs + """ builtins = KnownImageCrawlers._builtins() for _, bi_class in builtins.items(): KnownImageCrawlers._test(bi_class) diff --git a/tests/test_10_nichtparasoup/test_imagecrawler/test_reddit.py b/tests/test_10_nichtparasoup/test_imagecrawler/test_reddit.py index 2d60cf04..9f7f59b6 100644 --- a/tests/test_10_nichtparasoup/test_imagecrawler/test_reddit.py +++ b/tests/test_10_nichtparasoup/test_imagecrawler/test_reddit.py @@ -54,8 +54,9 @@ def test_check_config_wrong_value(self) -> None: with self.assertRaises(ValueError, msg=repr(config_in)): Reddit.check_config(config_in) + @unittest.skip("TODO: do we need this tested or even coded?") def test_check_config_not_existing(self) -> None: - self.skipTest('TODO do we need this tested or even coded?') + raise NotImplementedError class RedditBuildUriTest(unittest.TestCase): diff --git a/tests/test_10_nichtparasoup/test_webserver/test_webserver.py b/tests/test_10_nichtparasoup/test_webserver/test_webserver.py index d5e55561..fa6431e9 100644 --- a/tests/test_10_nichtparasoup/test_webserver/test_webserver.py +++ b/tests/test_10_nichtparasoup/test_webserver/test_webserver.py @@ -13,6 +13,7 @@ def setUp(self) -> None: def tearDown(self) -> None: del self.webserver + @unittest.skip("TODO: write the test") def test_webserver(self) -> None: - self.skipTest('TODO: write the test') # TODO: write tests # maybe this helps? http://werkzeug.palletsprojects.com/en/0.16.x/test/ + raise NotImplementedError()