click: click.Path returns str, not pathlib.Path

It’s surprising that INT returns an int, File a file, STRING a str, but Path a …str?

A click.Path parameter should return a pathlib.Path object.

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 21
  • Comments: 34 (28 by maintainers)

Commits related to this issue

Most upvoted comments

For the impatient, I defined my own like this. It accepts all the same options as click.Path:

class PathPath(click.Path):
    """A Click path argument that returns a pathlib Path, not a string"""
    def convert(self, value, param, ctx):
        return Path(super().convert(value, param, ctx))
@click.argument('input', type=PathPath(dir_okay=False))
def ...

(this usage style also feels cleaner to me than click.Path(...., converter=pathlib.Path), as well as more easily remembered. Path is built into Python’s standard library and widely used, so I think it’s worth a dedicated type.)

Thanks @jeremyh !

I have packaged this solution into https://pypi.org/project/click-pathlib, so you can use:

$ pip install click-pathlib
import click
import click_pathlib

@click.command('delete')
@click.argument(
    'existing_file',
    type=click_pathlib.Path(exists=True),
)
def delete(existing_file):
    existing_file.unlink()

Since PATH does not exist anyways we can do two things. One is we set up a default mapping for pathlib.Path as input type (similar to how we have a default type for str) being passed to click.Path(convert=pathlib.Path) and then add support for convert being passed to click.Path.

That way someone can also pass it through something else that does something interesting with the path.

An alternative (also depending on #1148) would be to follow @mitsuhiko’s idea in https://github.com/pallets/click/issues/405#issuecomment-324987608:

We just add click.PATH and use it in examples instead of click.Path, therefore encouraging click.PATH without breaking changes. This would be less disruptive.

Seeing as Python 2 is now dead and all, does it maybe make sense to now transition to using pathlib.Path as a default instead of a str value?

Hmm, just spitballing here, but maybe a transitional release could be done (after #1148 is merged). In Click 8, the following would raise a FutureWarning like this:

@click.argument('filename', type=click.Path())

You specified no Path converter. click.Path(converter=None) will result in a pathlib.Path object in Click 9. To avoid this warning, specify converter=str or converter=pathlib.Path.

And consequently, in Click 9 (or 10), the warning would be gone and the default changed.

The second one isn’t, Python 2 isn’t supported anymore so you’re free to move on and get rid of all hideous compatibility hacks 🎉

About the first … click has a lot of major version releases, and derive from your reluctance that they’re all less intrusive than this one?

I’m saying that this is a completely separate decision to make. But I forgot that we already announced dropped support for Python 2 so this would probably be fine to land in Click 8.

https://palletsproject.com/blog/ending-python2-support/

You know I mean that Python 2 is unmaintained as of 2 weeks ago. Supporting something that’s unmaintained is pretty futile.

err, #1148