Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pathlib Path objects should support __format__ #82403

Closed
tebeka mannequin opened this issue Sep 19, 2019 · 16 comments
Closed

pathlib Path objects should support __format__ #82403

tebeka mannequin opened this issue Sep 19, 2019 · 16 comments
Labels
3.8 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@tebeka
Copy link
Mannequin

tebeka mannequin commented Sep 19, 2019

BPO 38222
Nosy @brettcannon, @tebeka, @pitrou, @ericvsmith, @serhiy-storchaka, @zooba, @miss-islington, @nyuszika7h
PRs
  • bpo-38222: Add __format__ to pathlib.Path #16286
  • bpo-38222: Add __format__ to pathlib.Path #16287
  • [3.9] bpo-38822: Check specifically for a drive, not just a colon (GH-25540) #25542
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2019-09-19.20:54:43.264>
    created_at = <Date 2019-09-19.06:01:05.496>
    labels = ['3.8', 'type-bug', 'library']
    title = 'pathlib Path objects should support __format__'
    updated_at = <Date 2021-09-13.17:37:51.110>
    user = 'https://github.com/tebeka'

    bugs.python.org fields:

    activity = <Date 2021-09-13.17:37:51.110>
    actor = 'pitrou'
    assignee = 'none'
    closed = True
    closed_date = <Date 2019-09-19.20:54:43.264>
    closer = 'brett.cannon'
    components = ['Library (Lib)']
    creation = <Date 2019-09-19.06:01:05.496>
    creator = 'tebeka'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 38222
    keywords = ['patch']
    message_count = 16.0
    messages = ['352771', '352772', '352773', '352775', '352784', '352785', '352787', '352794', '352795', '352801', '352814', '391640', '401710', '401711', '401712', '401721']
    nosy_count = 8.0
    nosy_names = ['brett.cannon', 'tebeka', 'pitrou', 'eric.smith', 'serhiy.storchaka', 'steve.dower', 'miss-islington', 'nyuszika7h']
    pr_nums = ['16286', '16287', '25542']
    priority = 'normal'
    resolution = 'rejected'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue38222'
    versions = ['Python 3.8']

    @tebeka
    Copy link
    Mannequin Author

    tebeka mannequin commented Sep 19, 2019

    Currently pathlib.Path cannot be used with string formatting directives. IMO it should.

    >>> from pathlib import Path
    >>> path = Path('/path/to/enlightenment')
    >>> print(f'path is: {path:>50}')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported format string passed to PosixPath.__format__

    @tebeka tebeka mannequin added 3.8 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error labels Sep 19, 2019
    @serhiy-storchaka
    Copy link
    Member

    Convert it to string first:

        print(f'path is: {path!s:>50}')

    @ericvsmith
    Copy link
    Member

    I agree with Serhiy that !s solves the problem. But as a convenience it might be nice to add __format__. This issue pops up from time to time on Path and other types, and I don't think !s is very discoverable. Especially because formatting works with a specifier, but fails with one:

    >>> format(path)
    '/path/to/enlightenment'
    >>> format(path, '>50')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported format string passed to PosixPath.__format__

    @serhiy-storchaka
    Copy link
    Member

    Initially, the default __format__ converted the object to str and passed format specifier to str.__format__. This is defined in PEP-3101:

    class object:
        def __format__(self, format_spec):
            return format(str(self), format_spec)

    But later we changed the implementation, because this leaded to difficult to catch errors. Non-empty format specifier is now error in the default __format__.

    @ericvsmith
    Copy link
    Member

    Correct: this change was made specifically so that objects could add their own format specifiers at a later time. If I recall correctly, This change was precipitated by wanting to add datetime.__format__: this change broke existing uses for format() that formatted datetimes as strings.

    But the result is that objects that really just want to be formatted as strings need to have their own __format__ which returns format(str(self), format_spec).

    @serhiy-storchaka
    Copy link
    Member

    Or use !s or !r.

    In some cases it may be even better to use both convertions: f'{str(path)!r:>50}'.

    This is all application specific, so I do not think we should rethink our old decision. Explicit is better than implicit.

    @ericvsmith
    Copy link
    Member

    I don't think anyone is suggesting reverting the decision on object.__format__. That decision should stay.

    I think the suggestion is to add Path.__format__, which just converts to a string and formats with the given spec.

    Unless someone can think of a reason to have a different format specifier language for Path, I think this is a good usability improvement.

    @serhiy-storchaka
    Copy link
    Member

    I am -0 on this. It is a can of worms. Once we add a trivial __format__ in Path, we will need to handle numerous requests for adding a trivial __format__ in many other classes. It is better to teach users to use !s (and this works also on older Python versions!).

    As for Path, there many ways to convert it to string: str(), repr(), os.fspath(), os.fsdecode(), Path.as_posix(), Path.as_uri(), with possible normalization, converting to absolute or relative path. I would not bet that we will never have reasons to have a different format specifier language for Path.

    @ericvsmith
    Copy link
    Member

    I'm also -0 on it. It's up to Antoine.

    @tebeka
    Copy link
    Mannequin Author

    tebeka mannequin commented Sep 19, 2019

    I don't think it violates " Explicit is better than implicit."
    There's a lot of work done to make pathlib.Path objects work in places where str or bytes is expected (e.g PEP-519), IMO this is another case.

    @brettcannon
    Copy link
    Member

    I'm -1 as PEP-519 created __fspath__ specifically so that pathlib.Path wouldn't be confused as a string by accident. You can also use os.fspath() to get a string representation of the path itself.

    I also don't know if Antoine wants to make this sort of call for pathlib anymore as he isn't listed in https://devguide.python.org/experts/ or https://github.com/python/cpython/blob/master/.github/CODEOWNERS for pathlib anymore (and that was an explicit choice based on code history for the experts index).

    @zooba
    Copy link
    Member

    zooba commented Apr 22, 2021

    New changeset e07d809 by Steve Dower in branch 'master':
    bpo-38222: Check specifically for a drive, not just a colon (GH-25540)
    e07d809

    @nyuszika7h
    Copy link
    Mannequin

    nyuszika7h mannequin commented Sep 13, 2021

    I would like for this to be reconsidered. Yes, you can use str(), but converting back and forth becomes really clunky:

    log_dir = 'logs/{date}'
    log_file = Path(str(path).format(time.strftime('%Y-%m-%d')) / 'log.txt'

    @nyuszika7h
    Copy link
    Mannequin

    nyuszika7h mannequin commented Sep 13, 2021

    Sorry, that should have been:

    log_dir = Path('logs/{date}')

    @ericvsmith
    Copy link
    Member

    log_dir = Path('logs/{date}')
    log_file = Path(str(path).format(time.strftime('%Y-%m-%d')) / 'log.txt'

    (I think you're missing "date=" in the call to .format().)

    Could you show what you think this would look like if Path.__format__ existed? I don't think anyone's suggesting that path.format() would be added by this issue, but maybe that would be a reasonable proposal as a different issue.

    @pitrou
    Copy link
    Member

    pitrou commented Sep 13, 2021

    I would be in favour of adding Path.__format__, even though I'm not terribly convinced by the use case presented.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.8 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    5 participants