Skip to content

filedialog.askdirectory "Cancel" behaves differently under Linux and Windows (Wine) #103878

Closed

Description

@4LT

Bug report

Native Linux binary and Windows executable (under Wine) have different behaviors for tkinter's filedialog.askdirectory. Clicking "Cancel" results in a return value of () (empty tuple) under Linux, and "" for the Windows executable.

Your environment

  • CPython versions tested on:

3.11

  • Operating system and architecture:

Arch Linux 6.2.9 natively AND under Wine 8.5

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on Apr 26, 2023
  2. ronaldoussoren commented on Apr 29, 2023

    @ronaldoussoren
    Contributor

    On macOS this returns "".

  3. chrstphrchvz commented on May 3, 2023

    @chrstphrchvz
    Contributor

    The underlying Tcl/Tk command tk_chooseDirectory (as well as tk_getOpenFile and tk_getSaveFile) has implementations for each platform. From Tcl/Tk’s perspective, clicking “cancel” causes an empty string value to be returned regardless of platform. However incidental differences between these implementations are causing the returned empty string value to either be unshared and untyped on Win32 and Aqua, or highly shared and often having type (such as "list", since the empty string is the empty Tcl list) on X11. And in general Tkinter does not automatically convert a Tcl value to a Python string if it has a type (other than "string").

  4. chrstphrchvz commented on May 4, 2023

    @chrstphrchvz
    Contributor

    A similar issue was already addressed for tkinter.colorchooser.Chooser: #48017

  5. added a commit that references this issue on Oct 23, 2023
  6. serhiy-storchaka commented on Jan 18, 2024

    @serhiy-storchaka
    Member

    It would perhaps be more Pythonic to return None as a special value. Some other dialogs already return None if cancelled (for example askyesnocancel() and askstring()).

  7. gcerretani commented on Oct 27, 2025

    @gcerretani

    From https://docs.python.org/3/library/dialog.html:

    The [...] functions when called create a modal, native look-and-feel dialog, wait for the user’s selection, then return the selected value(s) or None to the caller.

  8. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Oct 27, 2025
  9. chrstphrchvz commented on Nov 1, 2025

    @chrstphrchvz
    Contributor

    From https://docs.python.org/3/library/dialog.html:

    The [...] functions when called create a modal, native look-and-feel dialog, wait for the user’s selection, then return the selected value(s) or None to the caller.

    I think it might be incidental that askopenfilename(), askopenfilenames(), asksaveasfilename(), and askdirectory() are documented as possibly returning None.

    The documentation there describes not just functions which return file/directory names (e.g. askopenfilename()), but also functions which do return either file objects or None (e.g. askopenfile()). When this documentation was written several years ago, both kinds of ask… functions were grouped together, and then the verbiage about returning None was added in response to this review comment from Mark Roseman (TkDocs.com author):

    I would suggest putting the ask* functions first, since those are the preferred interface. For each, mention that these are modal dialogs, also that return value may be None.

    …even though only some (not all) of the ask… functions return None in practice.

    Should the documented behavior still be considered the correct behavior?

  10. gcerretani commented on Nov 4, 2025

    @gcerretani

    Assuming the documentation is the correct behavior, in my code I just wrap those functions like:

    def askopenfilename(*args, **kwargs) -> str | None:
        """
        Same of tkfile.askopenfilename
    
        Add a workaround for https://github.com/python/cpython/issues/103878.
        """
        res = filedialog.askopenfilename(*args, **kwargs)
        return res if res else None

    In case this is what we want, probably it is sufficient to add something like that on:

  11. serhiy-storchaka commented on May 24, 2026

    @serhiy-storchaka
    Member

    The documentation is incorrect and should be changed to match the behavior. It is too late to change the behavior of the released Python versions.

    After fixing the documentation we can change the type of the returning value for future releases, to make it more stable and consistent.

  12. serhiy-storchaka commented on Jun 27, 2026

    @serhiy-storchaka
    Member

    The blanket "or None" wording quoted above was already corrected by the gh-86726 documentation overhaul, which now documents each function's real cancelled value (in main, 3.14 and 3.13).

    PR #152429 adds a note advising callers to test the result for truth rather than comparing it with a specific empty value, since its exact type ("", (), [] or None) is not stable across platforms and Tk versions.

    That covers the documentation side. Normalizing the return type itself — so that e.g. askdirectory() consistently returns "" rather than () — is a separate, behavior-changing fix for a future release; it remains open here (see also PR #111195).

  13. serhiy-storchaka commented on Jun 27, 2026

    @serhiy-storchaka
    Member

    PR #152435 normalizes the cancelled result on main: '' for askopenfilename()/asksaveasfilename()/askdirectory(), and an empty tuple for askopenfilenames(), dropping the platform-dependent ()/b''.

    It supersedes #111195 by deciding single-vs-multiple from the multiple option rather than the result type, so askopenfilenames()'s legitimate empty tuple is preserved. The doc half is #152429.

  14. added 9 commits that reference this issue on Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytopic-tkintertype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions