2

I have a Python program and am using Click to process the command line. I have a single command program, as in the example below. On Windows I would like to pass in a valid glob expression like *.py to Click 8.x and have the literal string "*.py" show up in the filepattern variable.

Click 8.x expands the glob patterns by default (this is different than 7.x). On Bash, if you quote the glob pattern, the shell doesn't do the expansion, and Click passes in the string. On Windows, the shell doesn't do the expansion and passes the string into Python. In this case Click expands them.

So the question here is how do I get the string "*.py" passed in as a string on Windows (if there are OR are not any files that match)? I only want to allow 1 argument (so nargs=1). This all works fine in Click 7.x.

The following example saved as mycommand.py:

import click

@click.command("mycommand")
@click.argument("filepattern", nargs=1, type=str)
def mycommand(filepattern):
    print(filepattern)


if __name__ == "__main__":
    mycommand()

If I have a directory full of, say Python files, if I invoke this as python mycommand.py somefile.py, it will succeed as one value gets passed into filepattern and it will echo somefile.py.

If I invoke as python mycommand.py *.py it fails with an error like:

Usage: mycommand.py [OPTIONS] FILEPATTERN
Try 'mycommand.py --help' for help.

Error: Got unexpected extra arguments (scratch.py mycommand.py ...)

I know there is an argument windows_expand_args for a click.group, but I can't puzzle out how to get it to work for a single command program.

2
  • The behavior shown is probably not a Windows-specific issue. Most shells or command-line interpreters perform glob-expansion before invoking the (Python) program, when argument passed unquoted (with exception to CMD.exe). See: Click is expanding globs in a string and I don't want it to. · Issue #2499 · pallets/click. Invoking python mycommand.py *.py on Linux I got same error. Commented Jun 20, 2024 at 10:14
  • 1
    This is a Windows specific issue with Click 8.x. The behavior was changed from 7.x. Glob patterns are now expanded by default on Windows. In bash, you can quote the expression - "*.py" - and get the string. On Windows, Click now expands the wildcards itself before passing the arguments into command. Commented Jun 20, 2024 at 16:00

1 Answer 1

0
+50

Research in Click's GitHub repository

A search for windows_expand_args in Click's GitHub repository gave the clue.

From click changelog, Version 8.0.1, released 2021-05-19:

  • Pass windows_expand_args=False when calling the main command to disable pattern expansion on Windows. There is no way to escape patterns in CMD, so if the program needs to pass them on as-is then expansion must be disabled. :issue:1901

Someone asked same question in the respective PR 1918:

How is this used? I tried:

import click

@click.group(windows_expand_args=False)
@click.pass_context
def cli(ctx):
   ...

and got this answer from the maintainer:

It's an argument to the main program.

cli(windows_expand_args=False)

Example to use windows_expand_args=False

As CrazyChucky already answered, invoke the @click.command decorated function with windows_expand_args as extra keyword argument (e.g. in your main like shown below):

import click

@click.command("mycommand")
@click.argument("filepattern", nargs=1, type=str)
def mycommand(filepattern):
    print(filepattern)


if __name__ == "__main__":
    import os
    print(f"Click {click.__version__} on {os.name}")
    mycommand(windows_expand_args = False)

Tests

On Linux

Could only test on Linux: failed, as expected by David Campbell's comment to the question 😉️.

(a) with 1 quoted argument containing a glob like *

python3 click_glob.py "*.py"

Click 8.0.4 on posix
*.py

(b) with 1 unquoted argument containing a glob like *

python3 click_glob.py *.py

Click 8.0.4 on posix
Usage: click_glob.py [OPTIONS] FILEPATTERN
Try 'click_glob.py --help' for help.

Error: Got unexpected extra argument (pdfminer_figures.py)

(c) with 2 quoted arguments

python3 click_glob.py "*.py" "invalid"

Click 8.0.4 on posix
Usage: click_glob.py [OPTIONS] FILEPATTERN
Try 'click_glob.py --help' for help.

Error: Got unexpected extra argument (invalid)

On Windows

Could not verify, since I have no Windows available. Maybe someone else can test on their Windows and edit this answer with results.

(a) with 1 quoted argument containing a glob like *

(b) with 1 unquoted argument containing a glob like *

(c) with 2 quoted arguments

Sign up to request clarification or add additional context in comments.

1 Comment

Perfect! Thanks! I found this github issue, which is how I knew the option existed. I had the mycommand function directly set as an entry point in my pyproject.toml file, so this approach was not evident to my brain. I have a bunch of commands in pyproject.toml, so really didn't want to re-engineer how I'm handling commandline arguments for file patterns in each of them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.