Skip to content

[WIP] add stubs for typing #231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[flake8]
per-file-ignores =
**/*.pyi:E252,E301,E302,E305,E501,E701,E704,F401,F811,F821
69 changes: 0 additions & 69 deletions .travis.yml

This file was deleted.

32 changes: 0 additions & 32 deletions appveyor.yml

This file was deleted.

8 changes: 8 additions & 0 deletions py/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from py._error import ErrorMaker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ErrorMaker is not exposed so I'd add it with underscore.


from . import path
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems better to me not to import here, but instead handle as a sub-package in the stubs. That is, add py/path/__init__.pyi. (We might want to separate the stubs to some separate source tree, if that's even possible, so it doesn't affect the real package).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to separate the stubs to some separate source tree, if that's even possible, so it doesn't affect the real package

py/path is empty without the stubs.
Do you mean to keep py/path/*.pyi there then, or do you mean to use something like py/_typed/…?

The idea of using the main __init__.pyi was to see what's really exposed/used - but I guess since it is used from/via py/path that is something mypy looks at also already.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw later that you already added py/path directory, so you can just delete this line already, as it's redundant with the subpackage.

My comment about "separate source tree" was that adding actual py/path directory might have some affect on runtime module resolution? With namespace packages and such? I.e. currently import py.path.foo goes thru the py import hackery to the private py._path package, but if you we add actual py/path directory does it break anything?

If not then great :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but I assume it is fine, since there is only .pyi, no .py.

from ._vendored_packages import iniconfig
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for iniconfig and io re. subpackages.

from .io import TerminalWriter

error: ErrorMaker
__version__: str
72 changes: 72 additions & 0 deletions py/_io/terminalwriter.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import ctypes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only types from this file that are exposed in py.io are the following, so I'd just leave those and delete everything else!

'TerminalWriter'      : '._io.terminalwriter:TerminalWriter',    
'ansi_print'          : '._io.terminalwriter:ansi_print',
'get_terminal_width'  : '._io.terminalwriter:get_terminal_width',

from py.builtin import bytes as bytes, text as text
from typing import Any, Optional

py3k: Any
py33: Any
win32_and_ctypes: bool
colorama: Any

def get_terminal_width(): ...

terminal_width: Any
char_width: Any

def get_line_width(text: Any): ...
def ansi_print(text: Any, esc: Any, file: Optional[Any] = ..., newline: bool = ..., flush: bool = ...) -> None: ...
def should_do_markup(file: Any): ...

class TerminalWriter:
stringio: Any = ...
encoding: Any = ...
hasmarkup: Any = ...
def __init__(self, file: Optional[Any] = ..., stringio: bool = ..., encoding: Optional[Any] = ...) -> None: ...
@property
def fullwidth(self): ...
@fullwidth.setter
def fullwidth(self, value: Any) -> None: ...
@property
def chars_on_current_line(self): ...
@property
def width_of_current_line(self): ...
def markup(self, text: Any, **kw: Any): ...
def sep(self, sepchar: Any, title: Optional[Any] = ..., fullwidth: Optional[Any] = ..., **kw: Any) -> None: ...
def write(self, msg: Any, **kw: Any) -> None: ...
def line(self, s: str = ..., **kw: Any) -> None: ...
def reline(self, line: Any, **kw: Any) -> None: ...

class Win32ConsoleWriter(TerminalWriter):
def write(self, msg: Any, **kw: Any) -> None: ...

class WriteFile:
encoding: Any = ...
def __init__(self, writemethod: Any, encoding: Optional[Any] = ...) -> None: ...
def write(self, data: Any) -> None: ...
def flush(self) -> None: ...
TerminalWriter = Win32ConsoleWriter
STD_OUTPUT_HANDLE: int
STD_ERROR_HANDLE: int
FOREGROUND_BLACK: int
FOREGROUND_BLUE: int
FOREGROUND_GREEN: int
FOREGROUND_RED: int
FOREGROUND_WHITE: int
FOREGROUND_INTENSITY: int
BACKGROUND_BLACK: int
BACKGROUND_BLUE: int
BACKGROUND_GREEN: int
BACKGROUND_RED: int
BACKGROUND_WHITE: int
BACKGROUND_INTENSITY: int
SHORT = ctypes.c_short

class COORD(ctypes.Structure): ...
class SMALL_RECT(ctypes.Structure): ...
class CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure): ...

def GetStdHandle(kind: Any): ...

SetConsoleTextAttribute: Any

def GetConsoleInfo(handle: Any): ...
def write_out(fil: Any, msg: Any) -> None: ...
1 change: 1 addition & 0 deletions py/path/__init__.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .local import LocalPath as local
72 changes: 72 additions & 0 deletions py/path/common.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from typing import Any, Optional

iswin32: Any
import_errors: Any

class Checkers:
path: Any = ...
def __init__(self, path: Any) -> None: ...
def dir(self) -> None: ...
def file(self) -> None: ...
def dotfile(self): ...
def ext(self, arg: Any): ...
def exists(self) -> None: ...
def basename(self, arg: Any): ...
def basestarts(self, arg: Any): ...
def relto(self, arg: Any): ...
def fnmatch(self, arg: Any): ...
def endswith(self, arg: Any): ...

class NeverRaised(Exception): ...

class PathBase:
strpath: str

Checkers: Any = ...
def __div__(self, other: Any): ...
__truediv__: Any = ...
def basename(self): ...
basename: Any = ...
def dirname(self): ...
dirname: Any = ...
def purebasename(self): ...
purebasename: Any = ...
def ext(self): ...
ext: Any = ...
def dirpath(self, *args: Any, **kwargs: Any): ...
def read_binary(self): ...
def read_text(self, encoding: Any): ...
def read(self, mode: str = ...): ...
def readlines(self, cr: int = ...): ...
def load(self): ...
def move(self, target: Any) -> None: ...
def check(self, **kw: Any): ...
def fnmatch(self, pattern: Any): ...
def relto(self, relpath: Any): ...
def ensure_dir(self, *args: Any): ...
def bestrelpath(self, dest: Any): ...
def exists(self): ...
def isdir(self): ...
def isfile(self): ...
def parts(self, reverse: bool = ...): ...
def common(self, other: Any): ...
def __add__(self, other: Any): ...
def __cmp__(self, other: Any): ...
def __lt__(self, other: Any) -> Any: ...
def visit(self, fil: Optional[Any] = ..., rec: Optional[Any] = ..., ignore: Any = ..., bf: bool = ..., sort: bool = ...) -> None: ...
def samefile(self, other: Any): ...
def __fspath__(self): ...

class Visitor:
rec: Any = ...
fil: Any = ...
ignore: Any = ...
breadthfirst: Any = ...
optsort: Any = ...
def __init__(self, fil: Any, rec: Any, ignore: Any, bf: Any, sort: Any) -> None: ...
def gen(self, path: Any) -> None: ...

class FNMatcher:
pattern: Any = ...
def __init__(self, pattern: Any) -> None: ...
def __call__(self, path: Any): ...
94 changes: 94 additions & 0 deletions py/path/local.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import sys
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For py.path, we should only expose class local. LocalPath is not importable directly, only as the py.path.local. And the SVN stuff I guess is dead and better to leave out.

Should remove everything else from this file and py/path/common.pyi or expose underscored if referenced indirectly by an exposed item.

from typing import Any, Optional

from . import common


def map_as_list(func: Any, iter: Any) -> Any: ...

ALLOW_IMPORTLIB_MODE: Any

class Stat:
def __getattr__(self, name: Any) -> Any: ...
path: Any = ...
def __init__(self, path: Any, osstatresult: Any) -> None: ...
@property
def owner(self) -> None: ...
@property
def group(self) -> None: ...
def isdir(self) -> None: ...
def isfile(self) -> None: ...
def islink(self) -> None: ...

class PosixPath(common.PathBase):
def chown(self, user: Any, group: Any, rec: int=...) -> Any: ...
def readlink(self) -> None: ...
def mklinkto(self, oldname: Any) -> None: ...
def mksymlinkto(self, value: Any, absolute: int=...) -> None: ...

def getuserid(user: Any) -> Any: ...
def getgroupid(group: Any) -> Any: ...

# FSBase = not iswin32 and PosixPath or common.PathBase
if sys.platform != 'win32':
FSBase = PosixPath
else:
FSBase = common.PathBase

class LocalPath(FSBase):
class ImportMismatchError(ImportError): ...
sep: Any = ...
class Checkers(common.Checkers):
def dir(self) -> None: ...
def file(self) -> None: ...
def exists(self) -> None: ...
def link(self) -> None: ...
def __init__(self, path: Optional[Any]=..., expanduser: bool=...) -> None: ...
def __hash__(self) -> Any: ...
def __eq__(self, other: Any) -> Any: ...
def __ne__(self, other: Any) -> Any: ...
def __lt__(self, other: Any) -> Any: ...
def __gt__(self, other: Any) -> Any: ...
def samefile(self, other: Any) -> Any: ...
def remove(self, rec: int=..., ignore_errors: bool=...) -> None: ...
def computehash(self, hashtype: str=..., chunksize: int=...) -> Any: ...
def new(self, **kw: Any) -> Any: ...
def dirpath(self, *args: Any, **kwargs: Any) -> Any: ...
def join(self, *args: Any, **kwargs: Any) -> Any: ...
def open(self, mode: str=..., ensure: bool=..., encoding: Optional[Any]=...) -> Any: ...
def islink(self) -> None: ...
def check(self, **kw: Any) -> Any: ...
def listdir(self, fil: Optional[Any]=..., sort: Optional[Any]=...) -> Any: ...
def size(self) -> None: ...
def mtime(self) -> None: ...
def copy(self, target: Any, mode: bool=..., stat: bool=...) -> Any: ...
def rename(self, target: Any) -> Any: ...
def dump(self, obj: Any, bin: int=...) -> None: ...
def mkdir(self, *args: Any) -> Any: ...
def write_binary(self, data: Any, ensure: bool=...) -> None: ...
def write_text(self, data: Any, encoding: Any, ensure: bool=...) -> None: ...
def write(self, data: Any, mode: str=..., ensure: bool=...) -> None: ...
def ensure(self, *args: Any, **kwargs: Any) -> Any: ...
def stat(self, raising: bool=...) -> Any: ...
def lstat(self) -> None: ...
def setmtime(self, mtime: Optional[Any]=...) -> Any: ...
def chdir(self) -> None: ...
def as_cwd(self) -> None: ...
def realpath(self) -> None: ...
def atime(self) -> None: ...
def chmod(self, mode: Any, rec: int=...) -> None: ...
def pypkgpath(self) -> None: ...
def pyimport(self, modname: Optional[Any]=..., ensuresyspath: bool=...) -> Any: ...
def sysexec(self, *argv: Any, **popen_opts: Any) -> Any: ...
def sysfind(cls: Any, name: Any, checker: Optional[Any]=..., paths: Optional[Any]=...) -> Any: ...
sysfind: Any = ...
@classmethod
def get_temproot(cls) -> None: ...
@classmethod
def mkdtemp(cls: Any, rootdir: Optional[Any]=...) -> Any: ...
def make_numbered_dir(prefix: str=..., rootdir: Optional[Any]=..., keep: Optional[int]=..., lock_timeout: int=...) -> Any: ...

def copymode(src: Any, dest: Any) -> None: ...
def copystat(src: Any, dest: Any) -> None: ...
def copychunked(src: Any, dest: Any) -> None: ...
def isimportable(name: Any) -> Any: ...
1 change: 1 addition & 0 deletions py/py.typed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
partial
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def main():
],
packages=find_packages(exclude=['tasks', 'testing']),
zip_safe=False,
package_data={
"": ["py.typed"],
},
)

if __name__ == '__main__':
Expand Down