from typing import ContextManager
from typing import Dict
from typing import List
+from typing import Literal
from typing import Optional
+from typing import overload
from typing import TextIO
from typing import Tuple
from typing import TYPE_CHECKING
"""
+@overload
+def get_x_argument(as_dictionary: Literal[False]) -> List[str]: ...
+@overload
+def get_x_argument(as_dictionary: Literal[True]) -> Dict[str, str]: ...
+@overload
def get_x_argument(
- as_dictionary: bool = False,
+ as_dictionary: bool = ...,
) -> Union[List[str], Dict[str, str]]:
"""Return the value(s) passed for the ``-x`` argument, if any.
return self.context_opts.get("tag", None)
@overload
- def get_x_argument( # type:ignore[misc]
- self, as_dictionary: Literal[False] = ...
- ) -> List[str]:
+ def get_x_argument(self, as_dictionary: Literal[False]) -> List[str]:
...
@overload
- def get_x_argument( # type:ignore[misc]
- self, as_dictionary: Literal[True] = ...
- ) -> Dict[str, str]:
+ def get_x_argument(self, as_dictionary: Literal[True]) -> Dict[str, str]:
+ ...
+
+ @overload
+ def get_x_argument(
+ self, as_dictionary: bool = ...
+ ) -> Union[List[str], Dict[str, str]]:
...
def get_x_argument(
):
ignore_items = IGNORE_ITEMS.get(file_key, set())
context_managers = CONTEXT_MANAGERS.get(file_key, [])
- if sys.version_info < (3, 9):
- raise RuntimeError("This script must be run with Python 3.9 or higher")
+ if sys.version_info < (3, 11):
+ raise RuntimeError(
+ "This script must be run with Python 3.11 or higher"
+ )
# When using an absolute path on windows, this will generate the correct
# relative path that shall be written to the top comment of the pyi file.
continue
meth = getattr(cls, name, None)
if callable(meth):
- _generate_stub_for_meth(
- cls, name, printer, env, name in context_managers
- )
+ # If there are overloads, generate only those
+ # Do not generate the base implementation to avoid mypy errors
+ overloads = typing.get_overloads(meth)
+ if overloads:
+ # use enumerate so we can generate docs on the last overload
+ for i, ovl in enumerate(overloads, 1):
+ _generate_stub_for_meth(
+ ovl,
+ cls,
+ printer,
+ env,
+ is_context_manager=name in context_managers,
+ is_overload=True,
+ base_method=meth,
+ gen_docs=(i == len(overloads)),
+ )
+ else:
+ _generate_stub_for_meth(
+ meth,
+ cls,
+ printer,
+ env,
+ is_context_manager=name in context_managers,
+ )
else:
_generate_stub_for_attr(cls, name, printer, env)
printer.writeline(f"{name}: {type_}")
-def _generate_stub_for_meth(cls, name, printer, env, is_context_manager):
-
- fn = getattr(cls, name)
+def _generate_stub_for_meth(
+ fn,
+ cls,
+ printer,
+ env,
+ is_context_manager,
+ is_overload=False,
+ base_method=None,
+ gen_docs=True,
+):
while hasattr(fn, "__wrapped__"):
fn = fn.__wrapped__
+ name = fn.__name__
spec = inspect_getfullargspec(fn)
try:
annotations = typing.get_type_hints(fn, env)
retval = re.sub("NoneType", "None", retval)
return retval
+ def _formatvalue(value):
+ return "=" + ("..." if value is Ellipsis else repr(value))
+
argspec = inspect_formatargspec(
*spec,
formatannotation=_formatannotation,
+ formatvalue=_formatvalue,
formatreturns=lambda val: f"-> {_formatannotation(val)}",
)
+
+ overload = "@overload" if is_overload else ""
contextmanager = "@contextmanager" if is_context_manager else ""
+
+ fn_doc = base_method.__doc__ if base_method else fn.__doc__
+ has_docs = gen_docs and fn_doc is not None
+ docs = '"""' + f"{fn_doc}" + '"""' if has_docs else ""
+
func_text = textwrap.dedent(
f"""
+ {overload}
{contextmanager}
- def {name}{argspec}:
- '''{fn.__doc__}'''
+ def {name}{argspec}: {"..." if not docs else ""}
+ {docs}
"""
)