@@ -405,6 +405,64 @@ common mistakes like unintentionally passing in ``None``.
405405
406406If in doubt, consider asking the library maintainers about their intent.
407407
408+ Common Patterns
409+ ===============
410+
411+ .. _stub-patterns :
412+
413+ This section documents common patterns that are useful in stub files.
414+
415+ Overloads and Flags
416+ -------------------
417+
418+ .. _overloads-and-flags :
419+
420+ Sometimes a function or method has a flag argument that changes the return type
421+ or other accepted argument types. For example, take the following function::
422+
423+ def open(name: str, mode: Literal["r", "w"] = "r") -> Reader | Writer:
424+ ...
425+
426+ We can express this case easily with two overloads::
427+
428+ @overload
429+ def open(name: str, mode: Literal["r"] = "r") -> Reader: ...
430+ @overload
431+ def open(name: str, mode: Literal["w"]) -> Writer: ...
432+
433+ The first overload is picked when the mode is ``"r" `` or not given, and the
434+ second overload is picked when the mode is ``"w" ``. But what if the first
435+ argument is optional?
436+
437+ ::
438+
439+ def open(name: str | None = None, mode: Literal["r", "w"] = "r") -> Reader | Writer:
440+ ...
441+
442+ Ideally we would be able to use the following overloads::
443+
444+ @overload
445+ def open(name: str | None = None, mode: Literal["r"] = "r") -> Reader: ...
446+ @overload
447+ def open(name: str | None = None, mode: Literal["w"]) -> Writer: ...
448+
449+ And while the first overload is fine, the second is a syntax error in Python,
450+ because non-default arguments cannot follow default arguments. To work around
451+ this, we need an extra overload::
452+
453+ @overload
454+ def open(name: str | None = None, mode: Literal["r"] = "r") -> Reader: ...
455+ @overload
456+ def open(name: str | None, mode: Literal["w"]) -> Writer: ...
457+ @overload
458+ def open(*, mode: Literal["w"]) -> Writer: ...
459+
460+ As before, the first overload is picked when the mode is ``"r" `` or not given.
461+ Otherwise, the second overload is used when ``open `` is called with an explicit
462+ ``name ``, e.g. ``open("file.txt", "w") `` or ``open(None, "w") ``. The third
463+ overload is used when ``open `` is called without a name , e.g.
464+ ``open(mode="w") ``.
465+
408466Style Guide
409467===========
410468
0 commit comments