Skip to content

Commit

Permalink
Add type stubs
Browse files Browse the repository at this point in the history
Add complete type stubs to the public interface of some of `py`s
modules.

The modules are those used by `pytest`. The types are marked as partial,
so uncovered modules should be unaffected.

Co-authored-by: Ran Benita <ran@unusedvar.com>.
  • Loading branch information
blueyed authored and bluetech committed Jun 23, 2020
1 parent d6aad84 commit 59fd0d5
Show file tree
Hide file tree
Showing 13 changed files with 561 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[flake8]
max-line-length = 120
per-file-ignores =
**/*.pyi:E252,E301,E302,E305,E501,E701,E704,F401,F811,F821
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.cache/
.tox/
__pycache__/
.mypy_cache/

*.pyc
*.pyo
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
1.9.0 (TBD)
===========

- Add type annotation stubs for the following modules:
* ``py.error``
* ``py.iniconfig``
* ``py.path`` (not including SVN paths)
* ``py.io``
* ``py.xml``
There are no plans to type other modules at this time.

The type annotations are provided in external .pyi files, not inline in the
code, and may therefore contain small errors or omissions. If you use ``py``
in conjunction with a type checker, and encounter any type errors you believe
should be accepted, please report it in an issue.

1.8.2 (2020-06-15)
==================

Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include setup.py
include LICENSE
include conftest.py
include tox.ini
recursive-include py *.pyi
graft doc
graft testing
global-exclude *.pyc
20 changes: 20 additions & 0 deletions py/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import Any

# py allows to use e.g. py.path.local even without importing py.path.
# So import implicitly.
from . import error
from . import iniconfig
from . import path
from . import io
from . import xml

__version__: str

# Untyped modules below here.
std: Any
test: Any
process: Any
apipkg: Any
code: Any
builtin: Any
log: Any
6 changes: 3 additions & 3 deletions py/_io/capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class TextIO(StringIO):
def write(self, data):
if not isinstance(data, unicode):
data = unicode(data, getattr(self, '_encoding', 'UTF-8'), 'replace')
StringIO.write(self, data)
return StringIO.write(self, data)
else:
TextIO = StringIO

Expand All @@ -24,7 +24,7 @@ class BytesIO(StringIO):
def write(self, data):
if isinstance(data, unicode):
raise TypeError("not a byte value: %r" %(data,))
StringIO.write(self, data)
return StringIO.write(self, data)

patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}

Expand Down Expand Up @@ -266,7 +266,7 @@ def readouterr(self):
err = self._readsnapshot(self.err.tmpfile)
else:
err = ""
return [out, err]
return out, err

def _readsnapshot(self, f):
f.seek(0)
Expand Down
129 changes: 129 additions & 0 deletions py/error.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
from typing import Any, Callable, TypeVar

_T = TypeVar('_T')

def checked_call(func: Callable[..., _T], *args: Any, **kwargs: Any) -> _T: ...
class Error(EnvironmentError): ...
class EPERM(Error): ...
class ENOENT(Error): ...
class ESRCH(Error): ...
class EINTR(Error): ...
class EIO(Error): ...
class ENXIO(Error): ...
class E2BIG(Error): ...
class ENOEXEC(Error): ...
class EBADF(Error): ...
class ECHILD(Error): ...
class EAGAIN(Error): ...
class ENOMEM(Error): ...
class EACCES(Error): ...
class EFAULT(Error): ...
class ENOTBLK(Error): ...
class EBUSY(Error): ...
class EEXIST(Error): ...
class EXDEV(Error): ...
class ENODEV(Error): ...
class ENOTDIR(Error): ...
class EISDIR(Error): ...
class EINVAL(Error): ...
class ENFILE(Error): ...
class EMFILE(Error): ...
class ENOTTY(Error): ...
class ETXTBSY(Error): ...
class EFBIG(Error): ...
class ENOSPC(Error): ...
class ESPIPE(Error): ...
class EROFS(Error): ...
class EMLINK(Error): ...
class EPIPE(Error): ...
class EDOM(Error): ...
class ERANGE(Error): ...
class EDEADLCK(Error): ...
class ENAMETOOLONG(Error): ...
class ENOLCK(Error): ...
class ENOSYS(Error): ...
class ENOTEMPTY(Error): ...
class ELOOP(Error): ...
class EWOULDBLOCK(Error): ...
class ENOMSG(Error): ...
class EIDRM(Error): ...
class ECHRNG(Error): ...
class EL2NSYNC(Error): ...
class EL3HLT(Error): ...
class EL3RST(Error): ...
class ELNRNG(Error): ...
class EUNATCH(Error): ...
class ENOCSI(Error): ...
class EL2HLT(Error): ...
class EBADE(Error): ...
class EBADR(Error): ...
class EXFULL(Error): ...
class ENOANO(Error): ...
class EBADRQC(Error): ...
class EBADSLT(Error): ...
class EDEADLOCK(Error): ...
class EBFONT(Error): ...
class ENOSTR(Error): ...
class ENODATA(Error): ...
class ETIME(Error): ...
class ENOSR(Error): ...
class ENONET(Error): ...
class ENOPKG(Error): ...
class EREMOTE(Error): ...
class ENOLINK(Error): ...
class EADV(Error): ...
class ESRMNT(Error): ...
class ECOMM(Error): ...
class EPROTO(Error): ...
class EMULTIHOP(Error): ...
class EDOTDOT(Error): ...
class EBADMSG(Error): ...
class EOVERFLOW(Error): ...
class ENOTUNIQ(Error): ...
class EBADFD(Error): ...
class EREMCHG(Error): ...
class ELIBACC(Error): ...
class ELIBBAD(Error): ...
class ELIBSCN(Error): ...
class ELIBMAX(Error): ...
class ELIBEXEC(Error): ...
class EILSEQ(Error): ...
class ERESTART(Error): ...
class ESTRPIPE(Error): ...
class EUSERS(Error): ...
class ENOTSOCK(Error): ...
class EDESTADDRREQ(Error): ...
class EMSGSIZE(Error): ...
class EPROTOTYPE(Error): ...
class ENOPROTOOPT(Error): ...
class EPROTONOSUPPORT(Error): ...
class ESOCKTNOSUPPORT(Error): ...
class ENOTSUP(Error): ...
class EOPNOTSUPP(Error): ...
class EPFNOSUPPORT(Error): ...
class EAFNOSUPPORT(Error): ...
class EADDRINUSE(Error): ...
class EADDRNOTAVAIL(Error): ...
class ENETDOWN(Error): ...
class ENETUNREACH(Error): ...
class ENETRESET(Error): ...
class ECONNABORTED(Error): ...
class ECONNRESET(Error): ...
class ENOBUFS(Error): ...
class EISCONN(Error): ...
class ENOTCONN(Error): ...
class ESHUTDOWN(Error): ...
class ETOOMANYREFS(Error): ...
class ETIMEDOUT(Error): ...
class ECONNREFUSED(Error): ...
class EHOSTDOWN(Error): ...
class EHOSTUNREACH(Error): ...
class EALREADY(Error): ...
class EINPROGRESS(Error): ...
class ESTALE(Error): ...
class EUCLEAN(Error): ...
class ENOTNAM(Error): ...
class ENAVAIL(Error): ...
class EISNAM(Error): ...
class EREMOTEIO(Error): ...
class EDQUOT(Error): ...
31 changes: 31 additions & 0 deletions py/iniconfig.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from typing import Callable, Iterator, Mapping, Optional, Tuple, TypeVar, Union
from typing_extensions import Final

_D = TypeVar('_D')
_T = TypeVar('_T')

class ParseError(Exception):
path: Final[str]
lineno: Final[int]
msg: Final[str]
def __init__(self, path: str, lineno: int, msg: str) -> None: ...

class _SectionWrapper:
config: Final[IniConfig]
name: Final[str]
def __init__(self, config: IniConfig, name: str) -> None: ...
def __getitem__(self, key: str) -> Optional[str]: ...
def __iter__(self) -> Iterator[str]: ...
def get(self, key: str, default: _D = ..., convert: Callable[[Optional[str]], _T] = ...) -> Union[_T, _D]: ...
def items(self) -> Iterator[Tuple[str, Optional[str]]]: ...
def lineof(self, name: str) -> Optional[int]: ...

class IniConfig:
path: Final[str]
sections: Final[Mapping[str, Mapping[str, Optional[str]]]]
def __init__(self, path: str, data: Optional[str] = None): ...
def __contains__(self, arg: str) -> bool: ...
def __getitem__(self, name: str) -> _SectionWrapper: ...
def __iter__(self) -> Iterator[_SectionWrapper]: ...
def get(self, section: str, name: str, default: _D = ..., convert: Callable[[Optional[str]], _T] = ...) -> Union[_T, _D]: ...
def lineof(self, section: str, name: Optional[str] = ...) -> Optional[int]: ...
130 changes: 130 additions & 0 deletions py/io.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
from io import StringIO as TextIO
from io import BytesIO as BytesIO
from typing import Any, AnyStr, Callable, Generic, IO, List, Optional, Text, Tuple, TypeVar, Union, overload
from typing_extensions import Final
import sys

_T = TypeVar("_T")

class FDCapture(Generic[AnyStr]):
def __init__(self, targetfd: int, tmpfile: Optional[IO[AnyStr]] = ..., now: bool = ..., patchsys: bool = ...) -> None: ...
def start(self) -> None: ...
def done(self) -> IO[AnyStr]: ...
def writeorg(self, data: AnyStr) -> None: ...

class StdCaptureFD:
def __init__(
self,
out: Union[bool, IO[str]] = ...,
err: Union[bool, IO[str]] = ...,
mixed: bool = ...,
in_: bool = ...,
patchsys: bool = ...,
now: bool = ...,
) -> None: ...
@classmethod
def call(cls, func: Callable[..., _T], *args: Any, **kwargs: Any) -> Tuple[_T, str, str]: ...
def reset(self) -> Tuple[str, str]: ...
def suspend(self) -> Tuple[str, str]: ...
def startall(self) -> None: ...
def resume(self) -> None: ...
def done(self, save: bool = ...) -> Tuple[IO[str], IO[str]]: ...
def readouterr(self) -> Tuple[str, str]: ...

class StdCapture:
def __init__(
self,
out: Union[bool, IO[str]] = ...,
err: Union[bool, IO[str]] = ...,
in_: bool = ...,
mixed: bool = ...,
now: bool = ...,
) -> None: ...
@classmethod
def call(cls, func: Callable[..., _T], *args: Any, **kwargs: Any) -> Tuple[_T, str, str]: ...
def reset(self) -> Tuple[str, str]: ...
def suspend(self) -> Tuple[str, str]: ...
def startall(self) -> None: ...
def resume(self) -> None: ...
def done(self, save: bool = ...) -> Tuple[IO[str], IO[str]]: ...
def readouterr(self) -> Tuple[IO[str], IO[str]]: ...

# XXX: The type here is not exactly right. If f is IO[bytes] and
# encoding is not None, returns some weird hybrid, not exactly IO[bytes].
def dupfile(
f: IO[AnyStr],
mode: Optional[str] = ...,
buffering: int = ...,
raising: bool = ...,
encoding: Optional[str] = ...,
) -> IO[AnyStr]: ...
def get_terminal_width() -> int: ...
def ansi_print(
text: Union[str, Text],
esc: Union[Union[str, Text], Tuple[Union[str, Text], ...]],
file: Optional[IO[Any]] = ...,
newline: bool = ...,
flush: bool = ...,
) -> None: ...
def saferepr(obj, maxsize: int = ...) -> str: ...

class TerminalWriter:
stringio: TextIO
encoding: Final[str]
hasmarkup: bool
def __init__(self, file: Optional[IO[str]] = ..., stringio: bool = ..., encoding: Optional[str] = ...) -> None: ...
@property
def fullwidth(self) -> int: ...
@fullwidth.setter
def fullwidth(self, value: int) -> None: ...
@property
def chars_on_current_line(self) -> int: ...
@property
def width_of_current_line(self) -> int: ...
def markup(
self,
text: str,
*,
black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ...,
cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ...,
Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ...,
blink: int = ..., invert: int = ...,
) -> str: ...
def sep(
self,
sepchar: str,
title: Optional[str] = ...,
fullwidth: Optional[int] = ...,
*,
black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ...,
cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ...,
Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ...,
blink: int = ..., invert: int = ...,
) -> None: ...
def write(
self,
msg: str,
*,
black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ...,
cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ...,
Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ...,
blink: int = ..., invert: int = ...,
) -> None: ...
def line(
self,
s: str = ...,
*,
black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ...,
cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ...,
Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ...,
blink: int = ..., invert: int = ...,
) -> None: ...
def reline(
self,
line: str,
*,
black: int = ..., red: int = ..., green: int = ..., yellow: int = ..., blue: int = ..., purple: int = ...,
cyan: int = ..., white: int = ..., Black: int = ..., Red: int = ..., Green: int = ..., Yellow: int = ...,
Blue: int = ..., Purple: int = ..., Cyan: int = ..., White: int = ..., bold: int = ..., light: int = ...,
blink: int = ..., invert: int = ...,
) -> None: ...
Loading

0 comments on commit 59fd0d5

Please sign in to comment.