Skip to content

Outdated/Incorrect annotations for os.startfile #10991

Closed
@Jakob-Stadler

Description

@Jakob-Stadler

In my opinion, the annotations for os.startfile have major problems that have been overlooked for the past few years.

For reference, the current annotations in stdlib/os__init__.pyi

if sys.platform == "win32":
    if sys.version_info >= (3, 8):
        def startfile(path: StrOrBytesPath, operation: str | None = None) -> None: ...
    else:
        def startfile(filepath: StrOrBytesPath, operation: str | None = None) -> None: ...

1. Renaming the first argument for filepath to path in >= 3.8

Is there reason why this change has been added? While the official docs list the argument name as path (docs), the CPython source code has the first argument as filepath (CPython/main), and firing up a REPL to check actual behavior mirrors the same:

>>> from os import startfile
>>> startfile(path='explorer')
Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    startfile(path='explorer')
TypeError: startfile() missing required argument 'filepath' (pos 1)

To me, it looks like a case of incorrect documentation that has been transferred into type annotations without checking whether it mirrors runtime behaviour.

2. Allowing None for operation argument

This is another annotation that conflicts with runtime behaviour:

>>> from os import startfile
>>> startfile(filepath='explorer', operation=None)
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    startfile(filepath='explorer', operation=None)
TypeError: startfile() argument 2 must be str, not None

I'll be honest, I'm not 100% sure what the correct default value is. Maybe just the empty string "" since the logic itself sits in Windows' own ShellExecuteW?

3. Missing arguments from >= 3.10

os.startfile gained additional arguments in Python 3.10, but they are all missing from the type annotations.

def startfile(
    filepath: StrOrBytesPath, 
    operation: str = "",  # Can't be None during runtime
    arguments: str = "",  # Can't be None during runtime
    cwd: StrOrBytesPath | None = None,  # Can be None during runtime
    show_cmd: int = 1  # Can't be None during runtime, 1 from CPython source
) -> None: ...

Disclaimer

I've been investigating this issue from my limited view point. There could be historic reasons why some things are the way they are. That's why I'm opening this as an Issue open for discussion instead of a PR. If you or somebody you know have more insight on this topic, please do share.

My proposal

If there are no mistakes in my assumptions, I would suggest the following annotations for os.startfile:

if sys.platform == "win32":
    if sys.version_info >= (3, 10):
        def startfile(filepath: StrOrBytesPath, operation: str = "", arguments: str = "", cwd: StrOrBytesPath | None = None, show_cmd: int = 1) -> None: ...
    else:
        def startfile(filepath: StrOrBytesPath, operation: str = '') -> None: ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions