Skip to content

Added support to .pyi stubs. #502

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

Merged
merged 6 commits into from
Dec 7, 2014
Merged
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
111 changes: 111 additions & 0 deletions misc/actions_stubs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env python3
import os
import shutil
from typing import Tuple, Any
try:
import click
except ImportError:
print("You need the module \'click\'")
exit(1)

base_path = os.getcwd()

# I don't know how to set callables with different args
def apply_all(func: Any, directory: str, extension: str,
to_extension: str='', exclude: Tuple[str]=('',),
recursive: bool=True, debug: bool=False) -> None:
excluded = [x+extension for x in exclude] if exclude else []
for p, d, files in os.walk(os.path.join(base_path,directory)):
for f in files:
if "{}".format(f) in excluded:
continue
inner_path = os.path.join(p,f)
if not inner_path.endswith(extension):
continue
if to_extension:
new_path = "{}{}".format(inner_path[:-len(extension)],to_extension)
func(inner_path,new_path)
else:
func(inner_path)
if not recursive:
break

def confirm(resp: bool=False, **kargs) -> bool:
kargs['rest'] = "to this {f2}/*{e2}".format(**kargs) if kargs.get('f2') else ''
prompt = "{act} all files {rec}matching this expression {f1}/*{e1} {rest}".format(**kargs)
prompt.format(**kargs)
prompt = "{} [{}]|{}: ".format(prompt, 'Y' if resp else 'N', 'n' if resp else 'y')
while True:
ans = input(prompt).lower()
if not ans:
return resp
if ans not in ['y','n']:
print( 'Please, enter (y) or (n).')
continue
if ans == 'y':
return True
else:
return False

actions = ['cp', 'mv', 'rm']
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--action', '-a', type=click.Choice(actions), required=True, help="What do I have to do :-)")
@click.option('--dir', '-d', 'directory', default='stubs', help="Directory to start search!")
@click.option('--ext', '-e', 'extension', default='.py', help="Extension \"from\" will be applied the action. Default .py")
@click.option('--to', '-t', 'to_extension', default='.pyi', help="Extension \"to\" will be applied the action if can. Default .pyi")
@click.option('--exclude', '-x', multiple=True, default=('__init__',), help="For every appear, will ignore this files. (can set multiples times)")
@click.option('--not-recursive', '-n', default=True, is_flag=True, help="Set if don't want to walk recursively.")
def main(action: str, directory: str, extension: str, to_extension: str,
exclude: Tuple[str], not_recursive: bool) -> None:
"""
This script helps to copy/move/remove files based on their extension.

The three actions will ask you for confirmation.

Examples (by default the script search in stubs directory):

- Change extension of all stubs from .py to .pyi:

python <script.py> -a mv

- Revert the previous action.

python <script.py> -a mv -e .pyi -t .py

- If you want to ignore "awesome.py" files.

python <script.py> -a [cp|mv|rm] -x awesome

- If you want to ignore "awesome.py" and "__init__.py" files.

python <script.py> -a [cp|mv|rm] -x awesome -x __init__

- If you want to remove all ".todo" files in "todo" directory, but not recursively:

python <script.py> -a rm -e .todo -d todo -r

"""
if action not in actions:
print("Your action have to be one of this: {}".format(', '.join(actions)))
return

rec = "[Recursively] " if not_recursive else ''
if not extension.startswith('.'):
extension = ".{}".format(extension)
if not to_extension.startswith('.'):
to_extension = ".{}".format(to_extension)
if directory.endswith('/'):
directory = directory[:-1]
if action == 'cp':
if confirm(act='Copy',rec=rec, f1=directory, e1=extension, f2=directory, e2=to_extension):
apply_all(shutil.copy, directory, extension, to_extension, exclude, not_recursive)
elif action == 'rm':
if confirm(act='Remove',rec=rec, f1=directory, e1=extension):
apply_all(os.remove, directory, extension, exclude=exclude, recursive=not_recursive)
elif action == 'mv':
if confirm(act='Move',rec=rec, f1=directory, e1=extension, f2=directory, e2=to_extension):
apply_all(shutil.move, directory, extension, to_extension, exclude, not_recursive)


if __name__ == '__main__':
main()
18 changes: 10 additions & 8 deletions mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
MODULE = 'module' # Build/run module as a script
TEST_BUILTINS = 'test-builtins' # Use stub builtins to speed up tests


# State ids. These describe the states a source file / module can be in a
# build.

Expand Down Expand Up @@ -228,6 +227,7 @@ def default_lib_path(data_dir: str, target: int, pyversion: int,


def lookup_program(module: str, lib_path: List[str]) -> str:
# Modules are .py and not .pyi
path = find_module(module, lib_path)
if path:
return path
Expand Down Expand Up @@ -856,14 +856,16 @@ def read_module_source_from_file(id: str,

def find_module(id: str, lib_path: List[str]) -> str:
"""Return the path of the module source file, or None if not found."""
extensions = ['.pyi', '.py']
for pathitem in lib_path:
comp = id.split('.')
path = os.path.join(pathitem, os.sep.join(comp[:-1]), comp[-1] + '.py')
text = ''
if not os.path.isfile(path):
path = os.path.join(pathitem, os.sep.join(comp), '__init__.py')
if os.path.isfile(path) and verify_module(id, path):
return path
for extension in extensions:
comp = id.split('.')
path = os.path.join(pathitem, os.sep.join(comp[:-1]), comp[-1] + extension)
text = ''
if not os.path.isfile(path):
path = os.path.join(pathitem, os.sep.join(comp), '__init__.py')
if os.path.isfile(path) and verify_module(id, path):
return path
return None


Expand Down
19 changes: 19 additions & 0 deletions mypy/test/data/check-modules.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

-- Test cases for the type checker.

[case testAccessImportedDefinitions]
Expand Down Expand Up @@ -137,6 +138,24 @@ def f() -> None: pass
[out]
main: In class "C":

[case testImportWithStub]
import _m
_m.f("hola")
[file _m.pyi]
def f(c:str) -> None: pass
[out]


[case testImportWithStubIncompatibleType]
import _m
_m.f("hola")
_m.f(12) # E: Argument 1 to "f" has incompatible type "int"; expected "str"
[file _m.py]
def f(c):
print(c)
[file _m.pyi]
def f(c:str) -> None: pass

[case testInvalidOperationsOnModules]
import m
import typing
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
for stub_dir in stub_dirs:
target = os.path.join('lib', 'mypy', 'stubs', py_version, stub_dir)
files = glob.glob(os.path.join(base, stub_dir, '*.py'))
files += glob.glob(os.path.join(base, stub_dir, '*.pyi'))
stubs.append((target, files))

classifiers = [
Expand Down
Empty file modified travis.sh
100644 → 100755
Empty file.