Description
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: ...