使用来自另一个脚本的参数启动 python 脚本,以编程方式设置 argparse 值

Posted

技术标签:

【中文标题】使用来自另一个脚本的参数启动 python 脚本,以编程方式设置 argparse 值【英文标题】:initiating python script with arguments from another script, setting argparse values programatically 【发布时间】:2021-09-13 00:43:27 【问题描述】:

我使用 python 包 (spotify_dl) 来生成一些文件。我是通过命令行手动完成的: spotify_dl -l spotify_playlist_link -o 下载目录

现在我想从另一个 python 脚本中执行此操作。

我查看了包代码并找到了 main 函数,但我不知道如何使用我选择的参数运行 main 函数 - 在 python 中。

例如我想要什么:

from spotify_dl import spotify_dl as sp_dl

if __name__=='__main__':
    destination_dir = r'D:\some\folder\path'
    playlists_url = ['url1','url2','url3',....]

    for url in playlists_url:
        sp_dl.spotify_dl(l=url,o=destination_dir)

为了更清楚,这里是 spotify_dl 主函数的实际代码:

#!/usr/bin/env python
import argparse
import json
import os
import sys
from logging import DEBUG
from pathlib import Path, PurePath

import spotipy
from spotipy.oauth2 import SpotifyClientCredentials

from spotify_dl.constants import VERSION
from spotify_dl.models import db, Song
from spotify_dl.scaffold import log, check_for_tokens
from spotify_dl.spotify import fetch_tracks, parse_spotify_url, validate_spotify_url, get_item_name
from spotify_dl.youtube import download_songs, default_filename, playlist_num_filename


def spotify_dl():
    """Main entry point of the script."""
    parser = argparse.ArgumentParser(prog='spotify_dl')
    parser.add_argument('-l', '--url', action="store",
                        help="Spotify Playlist link URL", type=str, required=True)
    parser.add_argument('-o', '--output', type=str, action='store',
                        help='Specify download directory.', required=True)
    parser.add_argument('-d', '--download', action='store_true',
                        help='Download using youtube-dl', default=True)
    parser.add_argument('-f', '--format_str', type=str, action='store',
                        help='Specify youtube-dl format string.',
                        default='bestaudio/best')
    parser.add_argument('-k', '--keep_playlist_order', default=False,
                        action='store_true',
                        help='Whether to keep original playlist ordering or not.')
    parser.add_argument('-m', '--skip_mp3', action='store_true',
                        help='Don\'t convert downloaded songs to mp3')
    parser.add_argument('-s', '--scrape', action="store",
                        help="Use html Scraper for YouTube Search", default=True)
    parser.add_argument('-V', '--verbose', action='store_true',
                        help='Show more information on what''s happening.')
    parser.add_argument('-v', '--version', action='store_true',
                        help='Shows current version of the program')
    args = parser.parse_args()

    if args.version:
        print("spotify_dl v".format(VERSION))
        exit(0)

    db.connect()
    db.create_tables([Song])
    if os.path.isfile(os.path.expanduser('~/.spotify_dl_settings')):
        with open(os.path.expanduser('~/.spotify_dl_settings')) as file:
            config = json.loads(file.read())

        for key, value in config.items():
            if value and (value.lower() == 'true' or value.lower() == 't'):
                setattr(args, key, True)
            else:
                setattr(args, key, value)

    if args.verbose:
        log.setLevel(DEBUG)

    log.info('Starting spotify_dl')
    log.debug('Setting debug mode on spotify_dl')

    if not check_for_tokens():
        exit(1)

    sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials())
    log.debug('Arguments: '.format(args))

    if args.url:
        valid_item = validate_spotify_url(args.url)

    if not valid_item:
        sys.exit(1)

    if args.output:
        item_type, item_id = parse_spotify_url(args.url)
        directory_name = get_item_name(sp, item_type, item_id)
        save_path = Path(PurePath.joinpath(Path(args.output), Path(directory_name)))
        save_path.mkdir(parents=True, exist_ok=True)
        log.info("Saving songs to: ".format(directory_name))

    songs = fetch_tracks(sp, item_type, args.url)
    if args.download is True:
        file_name_f = default_filename
        if args.keep_playlist_order:
            file_name_f = playlist_num_filename

        download_songs(songs, save_path, args.format_str, args.skip_mp3, args.keep_playlist_order, file_name_f)


if __name__ == '__main__':
    spotify_dl()

到目前为止,我可以看到提到 sys.argv,但也有一些 cmets 反对使用它。 我想要的是一种清晰的方法,我可以在没有并发症的情况下循环运行。

【问题讨论】:

【参考方案1】:

spotify_dl设计不好,我常用这个:

def parse_args(argv=None):
    parser = argparse.ArgumentParser()
    ...
    return parser.parse_args(argv)

def main(args):
    # run your code

if __name__ == "__main__":
    args = parse_args()
    main(args)

然后你可以在另一个脚本中导入这个第一个脚本并调用main函数:

from my_first_script import main

def a_function():
    args = namedtuple("args", ("arg1", ...))("value1")
    main(args)

但您可以通过覆盖sys.argv 来解决问题:

if __name__=='__main__':
    destination_dir = r'D:\some\folder\path'
    playlists_url = ['url1','url2','url3',....]

    for url in playlists_url:
        sys.argv = [sys.executable, "-o", destination_dir, "-l", url]
        sp_dl.spotify_dl()

【讨论】:

【参考方案2】:

您可以在此处使用subprocess。 我没有尝试您的示例,因为我没有安装这些库,但这是一个简单的示例。

首先,一个名为testpy.py 的简单命令行脚本具有以下内容:

import sys
import argparse
def check_arg(args=None):
    parser = argparse.ArgumentParser(prog='Test',
                     description='Test',
                     epilog='Test')
    parser.add_argument('-f', '--first',
                        help='First argument',
                        required='True')
    results = parser.parse_args(args)
    return (results.first)



def main():
    with open('test.txt', 'a') as file:
        file.write('Success, \n'.format(f))


if __name__ == '__main__':
    f = check_arg(sys.argv[1:])
    main()

这需要一个参数f 并使用提供的任何参数导出一个文本文件 (test.txt)。

这个脚本可以从下一个脚本运行(另存为新的脚本文件):

from subprocess import run, PIPE
args = ['python3', 'testpy.py', '-f', 'First input argument text']
res = run(args, stdout=PIPE, stderr=PIPE)

如果你运行它,你会看到文件test.txt 将被导出并且从这个脚本调用脚本testpy.py 是成功的。

【讨论】:

以上是关于使用来自另一个脚本的参数启动 python 脚本,以编程方式设置 argparse 值的主要内容,如果未能解决你的问题,请参考以下文章

无法在另一个 python 脚本中使用来自 python 函数的属性

使用命令行参数在另一个 Python 脚本中调用一个 Python 脚本

如何执行启动另一个 python 脚本的 python 宏?

如何在python中停止另一个已经运行的脚本?

python脚本中调用执行另一个带参数python脚本的问题

从另一个脚本 Python3 调用脚本