通过路径类型单击一旦导入的行为会有所不同

发布于 2025-02-07 14:19:31 字数 1451 浏览 1 评论 0原文

让我们想象我有一个简单的python脚本do_stuff.py在给定文件夹中列出了子文件夹:

import click

@click.command(help="Do stuff.")
@click.argument('datasets', type=click.Path(exists=True, readable=True, writable=True), nargs=-1)
def main(datasets):
    for dataset in datasets:
        print(dataset)

if __name__ == "__main__":
    main()

在我的情况下,它会在我运行python3 do_stuff.py./s3_data/时返回预期的文件夹列表。 lsc2/landsat_ot_c2_l2/*

./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220121
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220206
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220222
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220310

当我尝试从另一个脚本做同样的事情master.py.py.py时,导入do_stuff.py

from do_stuff import main as ds

ds('./s3_data/lsc2/landsat_ot_c2_l2/*')

当我运行时python3 master.py它返回:

Usage: master.py [OPTIONS] [DATASETS]...
Try 'master.py --help' for help.

Error: Invalid value for '[DATASETS]...': Path '/' is not writable.

如果我将master.py.py的最后一行修改为ds(['./ s3_data/lsc/lsc2/landsat_ot_ot_c2_l2/*'']))代码>,然后我得到:

Usage: master.py [OPTIONS] [DATASETS]...
Try 'master.py --help' for help.

Error: Invalid value for '[DATASETS]...': Path './s3_data/lsc2/landsat_ot_c2_l2/*' does not exist.

提前感谢您提供的任何帮助。

Let's imagine I have a simple Python script do_stuff.py that lists subfolders in a given folder:

import click

@click.command(help="Do stuff.")
@click.argument('datasets', type=click.Path(exists=True, readable=True, writable=True), nargs=-1)
def main(datasets):
    for dataset in datasets:
        print(dataset)

if __name__ == "__main__":
    main()

In my case it returns the expected list of folders when I run python3 do_stuff.py ./s3_data/lsc2/landsat_ot_c2_l2/*:

./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220121
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220206
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220222
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220310

When I try to do the same thing from another script master.py, importing do_stuff.py:

from do_stuff import main as ds

ds('./s3_data/lsc2/landsat_ot_c2_l2/*')

When I run python3 master.py it returns:

Usage: master.py [OPTIONS] [DATASETS]...
Try 'master.py --help' for help.

Error: Invalid value for '[DATASETS]...': Path '/' is not writable.

If I modify the last line of master.py into ds(['./s3_data/lsc2/landsat_ot_c2_l2/*']), then I get:

Usage: master.py [OPTIONS] [DATASETS]...
Try 'master.py --help' for help.

Error: Invalid value for '[DATASETS]...': Path './s3_data/lsc2/landsat_ot_c2_l2/*' does not exist.

Thanks in advance for any help you could provide.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花开浅夏 2025-02-14 14:19:31

为了使您充分理解看起来不同的行为,即您误以为“一旦导入路径类型的行为不同”,请建议您建议以下实验。在您的do_stuff.py中,检查什么参数单击在命令行'./ s3_data/lsc2/landsat_ot_c2_l2/*'是通过。这可以通过在main()

if __name__ == "__main__":
    import sys
    print(sys.argv)
    main()

现在运行之前添加这对行来完成:

$ python do_stuff.py ./s3_data/lsc2/landsat_ot_c2_l2/*
['do_stuff.py', './s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220121', './s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220206', './s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220222', './s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220310']
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220121
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220206
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220222
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220310

请注意它实际上是您拥有的四个文件的列表,而*无处不在在程序中可以看到。这是因为从外壳中,它自动在运行命令之前自动扩展通配符>,因此Python(因此单击)只会看到完全合格的文件名,并且循环愉快地运行。

一种简单的方法来模仿命令行(根据上一段中的链接线程,不必用set glob)来重复您从调用ds(Code> ds( './s3_data/lsc2/landsat_ot_c2_l2/*')是在通配符的路径中传递,而通配符将无法解析为任何

$ python do_stuff.py /tmp/a_dir_does_not_exist/*
Usage: do_stuff.py [OPTIONS] [DATASETS]...
Try 'do_stuff.py --help' for help.

Error: Invalid value for '[DATASETS]...': Path '/tmp/a_dir_does_not_exist/*' does not exist.

文件作为对程序的参数,在示例中,它模拟了调用ds(['/tmp/a_dir_does_not_exist/*'])根据问题中的失败示例。

现在,如果您想从python内使用相同的地球语法,则可以使用 glob.glob 功能复制外壳中的自动通配符扩展,示例:

>>> from do_stuff import main as ds
>>> from glob import glob
>>> ds(glob('./s3_data/lsc2/landsat_ot_c2_l2/*'))
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220310
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220222
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220206
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220121

In order for you to fully understand the behavior that looks different that you misattributed as "Click with Path type behavior differently once imported", may I recommend the following experiment. In your do_stuff.py, check what arguments click actually received when from the command line './s3_data/lsc2/landsat_ot_c2_l2/*' was passed. This may be done by adding these couple lines before main()

if __name__ == "__main__":
    import sys
    print(sys.argv)
    main()

Now run it:

$ python do_stuff.py ./s3_data/lsc2/landsat_ot_c2_l2/*
['do_stuff.py', './s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220121', './s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220206', './s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220222', './s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220310']
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220121
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220206
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220222
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220310

Note how it's actually a list of the four files that you have, and the * is nowhere to be seen inside the program. This is because from the shell, it automatically expands the wildcard character before the command is actually run, so Python (thus click) will only see the fully qualified filenames and the loop runs happily.

A easy way to emulate the failure from the command line (without having to muck about with set glob as per the linked thread in the previous paragraph) to repeat the failure you saw from calling ds('./s3_data/lsc2/landsat_ot_c2_l2/*') is to pass in a path with a wildcard that will not be resolved to any file, example:

$ python do_stuff.py /tmp/a_dir_does_not_exist/*
Usage: do_stuff.py [OPTIONS] [DATASETS]...
Try 'do_stuff.py --help' for help.

Error: Invalid value for '[DATASETS]...': Path '/tmp/a_dir_does_not_exist/*' does not exist.

Since the shell cannot expand that wildcard argument, its unmodifed form is passed as an argument to the program, and in the example it emulates calling ds(['/tmp/a_dir_does_not_exist/*']) as per the failed example in the question.

Now, if you want to use the same glob syntax from within Python, you may use the glob.glob function to replicate the automatic wildcard expansion in the shell, example:

>>> from do_stuff import main as ds
>>> from glob import glob
>>> ds(glob('./s3_data/lsc2/landsat_ot_c2_l2/*'))
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220310
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220222
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220206
./s3_data/lsc2/landsat_ot_c2_l2/LC08_L2SP_195027_20220121
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文