[BUG] Fix log-level not respected by loggers (#138)
* [BUG] Fix log-level not respected by loggers * _main * fix mocking
This commit is contained in:
parent
9fd97beca3
commit
2fde8f69c3
4 changed files with 150 additions and 129 deletions
122
src/ytdl_sub/cli/main.py
Normal file
122
src/ytdl_sub/cli/main.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import argparse
|
||||
import sys
|
||||
from typing import List
|
||||
from typing import Tuple
|
||||
|
||||
from ytdl_sub.cli.download_args_parser import DownloadArgsParser
|
||||
from ytdl_sub.cli.main_args_parser import parser
|
||||
from ytdl_sub.config.config_file import ConfigFile
|
||||
from ytdl_sub.config.preset import Preset
|
||||
from ytdl_sub.subscriptions.subscription import Subscription
|
||||
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
||||
from ytdl_sub.utils.logger import Logger
|
||||
|
||||
logger = Logger.get()
|
||||
|
||||
|
||||
def _download_subscriptions_from_yaml_files(
|
||||
config: ConfigFile, args: argparse.Namespace
|
||||
) -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
||||
"""
|
||||
Downloads all subscriptions from one or many subscription yaml files.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
config
|
||||
Configuration file
|
||||
args
|
||||
Arguments from argparse
|
||||
|
||||
Returns
|
||||
-------
|
||||
List of (subscription, transaction_log)
|
||||
"""
|
||||
preset_paths: List[str] = args.subscription_paths
|
||||
presets: List[Preset] = []
|
||||
output: List[Tuple[Subscription, FileHandlerTransactionLog]] = []
|
||||
|
||||
# Load all of the presets first to perform all validation before downloading
|
||||
for preset_path in preset_paths:
|
||||
presets += Preset.from_file_path(config=config, subscription_path=preset_path)
|
||||
|
||||
for preset in presets:
|
||||
subscription = Subscription.from_preset(preset=preset, config=config)
|
||||
|
||||
logger.info("Beginning subscription download for %s", subscription.name)
|
||||
transaction_log = subscription.download(dry_run=args.dry_run)
|
||||
|
||||
output.append((subscription, transaction_log))
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def _download_subscription_from_cli(
|
||||
config: ConfigFile, args: argparse.Namespace, extra_args: List[str]
|
||||
) -> Tuple[Subscription, FileHandlerTransactionLog]:
|
||||
"""
|
||||
Downloads a one-off subscription using the CLI
|
||||
|
||||
Parameters
|
||||
----------
|
||||
config
|
||||
Configuration file
|
||||
args
|
||||
Arguments from argparse
|
||||
extra_args
|
||||
Extra arguments from argparse that contain dynamic subscription options
|
||||
|
||||
Returns
|
||||
-------
|
||||
Subscription and its download transaction log
|
||||
"""
|
||||
dl_args_parser = DownloadArgsParser(
|
||||
extra_arguments=extra_args, config_options=config.config_options
|
||||
)
|
||||
subscription_args_dict = dl_args_parser.to_subscription_dict()
|
||||
|
||||
subscription_name = f"cli-dl-{dl_args_parser.get_args_hash()}"
|
||||
subscription_preset = Preset.from_dict(
|
||||
config=config,
|
||||
preset_name=subscription_name,
|
||||
preset_dict=subscription_args_dict,
|
||||
)
|
||||
|
||||
subscription = Subscription.from_preset(
|
||||
preset=subscription_preset,
|
||||
config=config,
|
||||
)
|
||||
|
||||
return subscription, subscription.download(dry_run=args.dry_run)
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Entrypoint for ytdl-sub, without the error handling
|
||||
"""
|
||||
# If no args are provided, print help and exit
|
||||
if len(sys.argv) < 2:
|
||||
parser.print_help()
|
||||
return
|
||||
|
||||
args, extra_args = parser.parse_known_args()
|
||||
|
||||
config: ConfigFile = ConfigFile.from_file_path(args.config).initialize()
|
||||
transaction_logs: List[Tuple[Subscription, FileHandlerTransactionLog]] = []
|
||||
if args.subparser == "sub":
|
||||
transaction_logs = _download_subscriptions_from_yaml_files(config=config, args=args)
|
||||
|
||||
# One-off download
|
||||
if args.subparser == "dl":
|
||||
transaction_logs.append(
|
||||
_download_subscription_from_cli(config=config, args=args, extra_args=extra_args)
|
||||
)
|
||||
|
||||
for subscription, transaction_log in transaction_logs:
|
||||
logger.info(
|
||||
"Downloads for %s:\n%s\n",
|
||||
subscription.name,
|
||||
transaction_log.to_output_message(subscription.output_directory),
|
||||
)
|
||||
|
||||
# Ran successfully, so we can delete the debug file
|
||||
Logger.cleanup(delete_debug_file=True)
|
||||
|
|
@ -27,6 +27,7 @@ parser.add_argument(
|
|||
help="level of logs to print to console, defaults to info",
|
||||
default=LoggerLevels.INFO.name,
|
||||
choices=LoggerLevels.names(),
|
||||
dest="ytdl_sub_log_level",
|
||||
)
|
||||
###################################################################################################
|
||||
# SUBSCRIPTION PARSER
|
||||
|
|
|
|||
|
|
@ -1,134 +1,29 @@
|
|||
import argparse
|
||||
import sys
|
||||
from typing import List
|
||||
from typing import Tuple
|
||||
|
||||
from ytdl_sub.cli.download_args_parser import DownloadArgsParser
|
||||
from ytdl_sub.cli.main_args_parser import parser
|
||||
from ytdl_sub.config.config_file import ConfigFile
|
||||
from ytdl_sub.config.preset import Preset
|
||||
from ytdl_sub.subscriptions.subscription import Subscription
|
||||
from ytdl_sub.utils.exceptions import ValidationException
|
||||
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
||||
from ytdl_sub.utils.logger import Logger
|
||||
|
||||
logger = Logger.get()
|
||||
|
||||
|
||||
def _download_subscriptions_from_yaml_files(
|
||||
config: ConfigFile, args: argparse.Namespace
|
||||
) -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
||||
"""
|
||||
Downloads all subscriptions from one or many subscription yaml files.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
config
|
||||
Configuration file
|
||||
args
|
||||
Arguments from argparse
|
||||
|
||||
Returns
|
||||
-------
|
||||
List of (subscription, transaction_log)
|
||||
"""
|
||||
preset_paths: List[str] = args.subscription_paths
|
||||
presets: List[Preset] = []
|
||||
output: List[Tuple[Subscription, FileHandlerTransactionLog]] = []
|
||||
|
||||
# Load all of the presets first to perform all validation before downloading
|
||||
for preset_path in preset_paths:
|
||||
presets += Preset.from_file_path(config=config, subscription_path=preset_path)
|
||||
|
||||
for preset in presets:
|
||||
subscription = Subscription.from_preset(preset=preset, config=config)
|
||||
|
||||
logger.info("Beginning subscription download for %s", subscription.name)
|
||||
transaction_log = subscription.download(dry_run=args.dry_run)
|
||||
|
||||
output.append((subscription, transaction_log))
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def _download_subscription_from_cli(
|
||||
config: ConfigFile, args: argparse.Namespace, extra_args: List[str]
|
||||
) -> Tuple[Subscription, FileHandlerTransactionLog]:
|
||||
"""
|
||||
Downloads a one-off subscription using the CLI
|
||||
|
||||
Parameters
|
||||
----------
|
||||
config
|
||||
Configuration file
|
||||
args
|
||||
Arguments from argparse
|
||||
extra_args
|
||||
Extra arguments from argparse that contain dynamic subscription options
|
||||
|
||||
Returns
|
||||
-------
|
||||
Subscription and its download transaction log
|
||||
"""
|
||||
dl_args_parser = DownloadArgsParser(
|
||||
extra_arguments=extra_args, config_options=config.config_options
|
||||
)
|
||||
subscription_args_dict = dl_args_parser.to_subscription_dict()
|
||||
|
||||
subscription_name = f"cli-dl-{dl_args_parser.get_args_hash()}"
|
||||
subscription_preset = Preset.from_dict(
|
||||
config=config,
|
||||
preset_name=subscription_name,
|
||||
preset_dict=subscription_args_dict,
|
||||
)
|
||||
|
||||
subscription = Subscription.from_preset(
|
||||
preset=subscription_preset,
|
||||
config=config,
|
||||
)
|
||||
|
||||
return subscription, subscription.download(dry_run=args.dry_run)
|
||||
|
||||
|
||||
def _main():
|
||||
"""
|
||||
Entrypoint for ytdl-sub, without the error handling
|
||||
"""
|
||||
# If no args are provided, print help and exit
|
||||
if len(sys.argv) < 2:
|
||||
parser.print_help()
|
||||
return
|
||||
# Set log level before any other ytdl-sub files are imported. That way, when loggers
|
||||
# get initialized, they will see the set log level
|
||||
args, _ = parser.parse_known_args()
|
||||
Logger.set_log_level(log_level_name=args.ytdl_sub_log_level)
|
||||
|
||||
args, extra_args = parser.parse_known_args()
|
||||
# pylint: disable=import-outside-toplevel
|
||||
import ytdl_sub.cli.main
|
||||
|
||||
config: ConfigFile = ConfigFile.from_file_path(args.config).initialize()
|
||||
Logger.set_log_level(log_level_name=args.log_level)
|
||||
# pylint: enable=import-outside-toplevel
|
||||
|
||||
transaction_logs: List[Tuple[Subscription, FileHandlerTransactionLog]] = []
|
||||
if args.subparser == "sub":
|
||||
transaction_logs = _download_subscriptions_from_yaml_files(config=config, args=args)
|
||||
|
||||
# One-off download
|
||||
if args.subparser == "dl":
|
||||
transaction_logs.append(
|
||||
_download_subscription_from_cli(config=config, args=args, extra_args=extra_args)
|
||||
)
|
||||
|
||||
for subscription, transaction_log in transaction_logs:
|
||||
logger.info(
|
||||
"Downloads for %s:\n%s\n",
|
||||
subscription.name,
|
||||
transaction_log.to_output_message(subscription.output_directory),
|
||||
)
|
||||
|
||||
# Ran successfully, so we can delete the debug file
|
||||
Logger.cleanup(delete_debug_file=True)
|
||||
ytdl_sub.cli.main.main()
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Entrypoint for ytdl-sub
|
||||
"""
|
||||
logger = Logger.get()
|
||||
try:
|
||||
_main()
|
||||
except ValidationException as validation_exception:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import contextlib
|
||||
import logging
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
|
|
@ -39,25 +40,27 @@ def test_main_success(mock_sys_exit):
|
|||
|
||||
def test_main_validation_error(capsys, mock_sys_exit):
|
||||
validation_exception = ValidationException("test")
|
||||
with mock_sys_exit(expected_exit_code=1):
|
||||
with patch("src.ytdl_sub.main._main", side_effect=validation_exception):
|
||||
with patch("src.ytdl_sub.main.logger") as mock_logger:
|
||||
main()
|
||||
with mock_sys_exit(expected_exit_code=1), patch(
|
||||
"src.ytdl_sub.main._main", side_effect=validation_exception
|
||||
), patch.object(logging.Logger, "error") as mock_logger:
|
||||
main()
|
||||
|
||||
assert mock_logger.error.call_count == 1
|
||||
assert mock_logger.error.call_args.args[0] == validation_exception
|
||||
assert mock_logger.call_count == 1
|
||||
assert mock_logger.call_args.args[0] == validation_exception
|
||||
|
||||
|
||||
def test_main_uncaught_error(capsys, mock_sys_exit, expected_uncaught_error_message):
|
||||
uncaught_error = ValueError("test")
|
||||
with mock_sys_exit(expected_exit_code=1):
|
||||
with patch("src.ytdl_sub.main._main", side_effect=uncaught_error):
|
||||
with patch("src.ytdl_sub.main.logger") as mock_logger:
|
||||
main()
|
||||
with mock_sys_exit(expected_exit_code=1), patch(
|
||||
"src.ytdl_sub.main._main", side_effect=uncaught_error
|
||||
), patch.object(logging.Logger, "exception") as mock_exception, patch.object(
|
||||
logging.Logger, "error"
|
||||
) as mock_error:
|
||||
main()
|
||||
|
||||
assert mock_logger.exception.call_count == 1
|
||||
assert mock_logger.exception.call_args.args[0] == "An uncaught error occurred:"
|
||||
assert mock_exception.call_count == 1
|
||||
assert mock_exception.call_args.args[0] == "An uncaught error occurred:"
|
||||
|
||||
assert mock_logger.error.call_count == 1
|
||||
assert mock_logger.error.call_args.args[0] == expected_uncaught_error_message
|
||||
assert mock_logger.error.call_args.args[1] == Logger.debug_log_filename()
|
||||
assert mock_error.call_count == 1
|
||||
assert mock_error.call_args.args[0] == expected_uncaught_error_message
|
||||
assert mock_error.call_args.args[1] == Logger.debug_log_filename()
|
||||
|
|
|
|||
Loading…
Reference in a new issue