# Buggy code
def get_arguments(raw_args=None, to_group=True, to_merge=True):
    parser = argparse.ArgumentParser(
        description="Download and convert songs from Spotify, Youtube etc.",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )

    if to_merge:
        config_file = os.path.join(sys.path[0], "config.yml")
        config = merge(default_conf["spotify-downloader"], get_config(config_file))
    else:
        config = default_conf["spotify-downloader"]

    if to_group:
        group = parser.add_mutually_exclusive_group(required=True)

        group.add_argument("-s", "--song", help="download song by spotify link or name")
        group.add_argument("-l", "--list", help="download songs from a file")
        group.add_argument(
            "-p",
            "--playlist",
            help="load songs from playlist URL into <playlist_name>.txt",
        )
        group.add_argument(
            "-b", "--album", help="load songs from album URL into <album_name>.txt"
        )
        group.add_argument(
            "-u",
            "--username",
            help="load songs from user's playlist into <playlist_name>.txt",
        )

    parser.add_argument(
        "-m",
        "--manual",
        default=config["manual"],
        help="choose the song to download manually",
        action="store_true",
    )
    parser.add_argument(
        "-nm",
        "--no-metadata",
        default=config["no-metadata"],
        help="do not embed metadata in songs",
        action="store_true",
    )
    parser.add_argument(
        "-a",
        "--avconv",
        default=config["avconv"],
        help="Use avconv for conversion otherwise set defaults to ffmpeg",
        action="store_true",
    )
    parser.add_argument(
        "-f",
        "--folder",
        default=os.path.relpath(config["folder"], os.getcwd()),
        help="path to folder where files will be stored in",
    )
    parser.add_argument(
        "--overwrite",
        default=config["overwrite"],
        help="change the overwrite policy",
        choices={"prompt", "force", "skip"},
    )
    parser.add_argument(
        "-i",
        "--input-ext",
        default=config["input-ext"],
        help="prefered input format .m4a or .webm (Opus)",
    )
    parser.add_argument(
        "-o",
        "--output-ext",
        default=config["output-ext"],
        help="prefered output extension .mp3 or .m4a (AAC)",
    )
    parser.add_argument(
        "-ff",
        "--file-format",
        default=config["file-format"],
        help="File format to save the downloaded song with, each tag "
        "is surrounded by curly braces. Possible formats: "
        "{}".format([internals.formats[x] for x in internals.formats]),
        action="store_true",
    )
    parser.add_argument(
        "-dm",
        "--download-only-metadata",
        default=config["download-only-metadata"],
        help="download songs for which metadata is found",
        action="store_true",
    )
    parser.add_argument(
        "-d",
        "--dry-run",
        default=config["dry-run"],
        help="Show only track title and YouTube URL",
        action="store_true",
    )
    parser.add_argument(
        "-mo",
        "--music-videos-only",
        default=config["music-videos-only"],
        help="Search only for music on Youtube",
        action="store_true",
    )
    parser.add_argument(
        "-ns",
        "--no-spaces",
        default=config["no-spaces"],
        help="Replace spaces with underscores in file names",
        action="store_true",
    )
    parser.add_argument(
        "-ll",
        "--log-level",
        default=config["log-level"],
        choices=_LOG_LEVELS_STR,
        type=str.upper,
        help="set log verbosity",
    )
    parser.add_argument(
        "-c", "--config", default=None, help="Replace with custom config.yml file"
    )

    parsed = parser.parse_args(raw_args)

    if parsed.config is not None and to_merge:
        parsed = override_config(parsed.config, parser)

    parsed.log_level = log_leveller(parsed.log_level)

    return parsed


# Traceback (urllib.error.HTTPError)
$ python ./spotdl.py -l ./playlist.txt -f /d/Music\ 02/ --log-level DEBUG

DEBUG: Python version: 3.6.1 |Anaconda 4.4.0 (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]
DEBUG: Platform: Windows-10-10.0.14393-SP0
DEBUG: {'album': None,
'avconv': False,
'config': None,
'download_only_metadata': False,
'dry_run': False,
'file_format': '{artist} - {track_name}',
'folder': 'D:/Music 02/',
'input_ext': '.m4a',
'list': './playlist.txt',
'log_level': 10,
'manual': False,
'music_videos_only': False,
'no_metadata': False,
'no_spaces': False,
'output_ext': '.mp3',
'overwrite': 'prompt',
'playlist': None,
'song': None,
'username': None}
INFO: Preparing to download 3 songs

DEBUG: Fetching metadata for given track URL
DEBUG: Fetching lyrics
<<(Truncated Meta Output)>>
DEBUG: query: {'part': 'snippet', 'maxResults': 50, 'type': 'video', 'q': 'Arctic Monkeys - R U Mine?'}
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\site-packages\pafy\util.py", line 34, in call_gdata
data = g.opener.open(url).read().decode('utf-8')
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 532, in open
response = meth(req, response)
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 642, in http_response
'http', request, response, code, msg, hdrs)
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 570, in error
return self._call_chain(*args)
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 504, in _call_chain
result = func(*args)
File "C:\ProgramData\Anaconda3\lib\urllib\request.py", line 650, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "./spotdl.py", line 185, in <module>
download_list(text_file=const.args.list)
File "./spotdl.py", line 79, in download_list
download_single(raw_song, number=number)
File "./spotdl.py", line 116, in download_single
content = youtube_tools.go_pafy(raw_song, meta_tags)
File "C:\Users\Jason Cemra\Downloads\spotify-downloader-master\core\youtube_tools.py", line 22, in go_pafy
track_url = generate_youtube_url(raw_song, meta_tags)
File "C:\Users\Jason Cemra\Downloads\spotify-downloader-master\core\youtube_tools.py", line 84, in generate_youtube_url
data = pafy.call_gdata('search', query)
File "C:\ProgramData\Anaconda3\lib\site-packages\pafy\util.py", line 42, in call_gdata
raise GdataError(errmsg)
pafy.util.GdataError: Youtube Error 403: The request cannot be completed because you have exceeded your <a href="/youtube/v3/getting-started#quota">quota</a>.

# Fixed code
def get_arguments(raw_args=None, to_group=True, to_merge=True):
    parser = argparse.ArgumentParser(
        description="Download and convert songs from Spotify, Youtube etc.",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )

    if to_merge:
        config_file = os.path.join(sys.path[0], "config.yml")
        config = merge(default_conf["spotify-downloader"], get_config(config_file))
    else:
        config = default_conf["spotify-downloader"]

    if to_group:
        group = parser.add_mutually_exclusive_group(required=True)

        group.add_argument("-s", "--song", help="download song by spotify link or name")
        group.add_argument("-l", "--list", help="download songs from a file")
        group.add_argument(
            "-p",
            "--playlist",
            help="load songs from playlist URL into <playlist_name>.txt",
        )
        group.add_argument(
            "-b", "--album", help="load songs from album URL into <album_name>.txt"
        )
        group.add_argument(
            "-u",
            "--username",
            help="load songs from user's playlist into <playlist_name>.txt",
        )

    parser.add_argument(
        "-m",
        "--manual",
        default=config["manual"],
        help="choose the song to download manually",
        action="store_true",
    )
    parser.add_argument(
        "-nm",
        "--no-metadata",
        default=config["no-metadata"],
        help="do not embed metadata in songs",
        action="store_true",
    )
    parser.add_argument(
        "-a",
        "--avconv",
        default=config["avconv"],
        help="Use avconv for conversion otherwise set defaults to ffmpeg",
        action="store_true",
    )
    parser.add_argument(
        "-f",
        "--folder",
        default=os.path.relpath(config["folder"], os.getcwd()),
        help="path to folder where files will be stored in",
    )
    parser.add_argument(
        "--overwrite",
        default=config["overwrite"],
        help="change the overwrite policy",
        choices={"prompt", "force", "skip"},
    )
    parser.add_argument(
        "-i",
        "--input-ext",
        default=config["input-ext"],
        help="prefered input format .m4a or .webm (Opus)",
    )
    parser.add_argument(
        "-o",
        "--output-ext",
        default=config["output-ext"],
        help="prefered output extension .mp3 or .m4a (AAC)",
    )
    parser.add_argument(
        "-ff",
        "--file-format",
        default=config["file-format"],
        help="File format to save the downloaded song with, each tag "
        "is surrounded by curly braces. Possible formats: "
        "{}".format([internals.formats[x] for x in internals.formats]),
        action="store_true",
    )
    parser.add_argument(
        "-dm",
        "--download-only-metadata",
        default=config["download-only-metadata"],
        help="download songs for which metadata is found",
        action="store_true",
    )
    parser.add_argument(
        "-d",
        "--dry-run",
        default=config["dry-run"],
        help="Show only track title and YouTube URL",
        action="store_true",
    )
    parser.add_argument(
        "-mo",
        "--music-videos-only",
        default=config["music-videos-only"],
        help="Search only for music on Youtube",
        action="store_true",
    )
    parser.add_argument(
        "-ns",
        "--no-spaces",
        default=config["no-spaces"],
        help="Replace spaces with underscores in file names",
        action="store_true",
    )
    parser.add_argument(
        "-ll",
        "--log-level",
        default=config["log-level"],
        choices=_LOG_LEVELS_STR,
        type=str.upper,
        help="set log verbosity",
    )
    parser.add_argument(
        "-yk",
        "--youtube-api-key",
        default=config["youtube-api-key"],
        help=argparse.SUPPRESS,
    )
    parser.add_argument(
        "-c", "--config", default=None, help="Replace with custom config.yml file"
    )

    parsed = parser.parse_args(raw_args)

    if parsed.config is not None and to_merge:
        parsed = override_config(parsed.config, parser)

    parsed.log_level = log_leveller(parsed.log_level)

    return parsed