Skip to content

Commit

Permalink
Fixes MyPy errors
Browse files Browse the repository at this point in the history
  • Loading branch information
evhub committed Oct 16, 2016
1 parent d137c2e commit 11f67aa
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 44 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ global-include *.txt
global-include *.rst
global-include *.md
global-include *.json
global-include *.pyi
55 changes: 35 additions & 20 deletions coconut/command/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,30 @@
)
from coconut.logging import logger
from coconut.constants import (
fixpath,
code_exts,
comp_ext,
watch_interval,
tutorial_url,
documentation_url,
icoconut_kernel_dirs,
minimum_recursion_limit,
stub_dir,
)
from coconut.command.util import (
openfile,
writefile,
readfile,
fixpath,
showpath,
rem_encoding,
Runner,
multiprocess_wrapper,
Prompt,
ensure_time_elapsed,
handle_broken_process_pool,
handling_broken_process_pool,
kill_children,
run_cmd,
in_mypy_path,
)
from coconut.compiler.header import gethash
from coconut.command.cli import arguments
Expand Down Expand Up @@ -231,7 +233,7 @@ def register_error(self, code=1, errmsg=None):
def handling_exceptions(self):
"""Performs proper exception handling."""
try:
with handle_broken_process_pool():
with handling_broken_process_pool():
yield
except SystemExit as err:
self.register_error(err.code)
Expand All @@ -250,7 +252,9 @@ def compile_path(self, path, write=True, package=None, run=False, force=False):
if os.path.isfile(path):
if package is None:
package = False
self.compile_file(path, write, package, run, force)
destpath = self.compile_file(path, write, package, run, force)
if destpath is not None:
self.run_mypy(destpath)
elif os.path.isdir(path):
if package is None:
package = True
Expand All @@ -260,26 +264,26 @@ def compile_path(self, path, write=True, package=None, run=False, force=False):

def compile_folder(self, directory, write=True, package=True, run=False, force=False):
"""Compiles a directory."""
filepaths = []
for dirpath, dirnames, filenames in os.walk(directory):
if write is None or write is True:
writedir = write
else:
writedir = os.path.join(write, os.path.relpath(dirpath, directory))
for filename in filenames:
if os.path.splitext(filename)[1] in code_exts:
self.compile_file(os.path.join(dirpath, filename), writedir, package, run, force, allow_mypy=False)
destpath = self.compile_file(os.path.join(dirpath, filename), writedir, package, run, force)
if destpath is not None:
filepaths.append(destpath)
for name in dirnames[:]:
if name != "." * len(name) and name.startswith("."):
if logger.verbose:
logger.show_tabulated("Skipped directory", name, "(explicitly pass as source to override).")
dirnames.remove(name) # directories removed from dirnames won't appear in further os.walk iteration
if write is True:
self.run_mypy(directory)
elif write is not None:
self.run_mypy(write)
self.run_mypy(*filepaths)

def compile_file(self, filepath, write=True, package=False, run=False, force=False, allow_mypy=True):
"""Compiles a file."""
def compile_file(self, filepath, write=True, package=False, run=False, force=False):
"""Compiles a file and returns the compiled file's path."""
if write is None:
destpath = None
elif write is True:
Expand All @@ -290,12 +294,11 @@ def compile_file(self, filepath, write=True, package=False, run=False, force=Fal
base, ext = os.path.splitext(os.path.splitext(destpath)[0])
if not ext:
ext = comp_ext
destpath = base + ext
if filepath == destpath:
raise CoconutException("cannot compile " + showpath(filepath) + " to itself (incorrect file extension)")
destpath = fixpath(base + ext)
if filepath == destpath:
raise CoconutException("cannot compile " + showpath(filepath) + " to itself (incorrect file extension)")
self.compile(filepath, destpath, package, run, force)
if allow_mypy and destpath is not None:
self.run_mypy(destpath)
return destpath

def compile(self, codepath, destpath=None, package=False, run=False, force=False):
"""Compiles a source Coconut file to a destination Python file."""
Expand Down Expand Up @@ -395,7 +398,9 @@ def running_jobs(self):

def create_package(self, dirpath):
"""Sets up a package directory."""
filepath = os.path.join(fixpath(dirpath), "__coconut__.py")
dirpath = fixpath(dirpath)

filepath = os.path.join(dirpath, "__coconut__.py")
with openfile(filepath, "w") as opened:
writefile(opened, self.comp.headers("package"))

Expand Down Expand Up @@ -470,10 +475,10 @@ def execute(self, compiled=None, path=None, use_eval=False, allow_show=True):
if compiled is not None:
if allow_show and self.show:
print(compiled)
self.run_mypy("-c", compiled)
if path is not None: # path means header is included, and thus encoding must be removed
compiled = rem_encoding(compiled)
self.runner.run(compiled, use_eval=use_eval, path=path, all_errors_exit=(path is not None))
self.run_mypy("-c", self.runner.was_run_code())

def execute_file(self, destpath):
"""Executes compiled file."""
Expand All @@ -495,23 +500,32 @@ def launch_documentation(self):
"""Opens the Coconut documentation."""
webbrowser.open(documentation_url, 2)

@property
def mypy(self):
"""Whether using MyPy or not."""
return self.mypy_args is not None

def run_mypy(self, *args):
"""Run MyPy with arguments."""
if self.mypy_args is not None:
if self.mypy:
args = ["mypy"] + list(args)

for arg in self.mypy_args:
if arg == "--fast-parser":
logger.warn("unnecessary --mypy argument", arg, extra="passed automatically if available")
elif arg == "--py2" or arg == "-2":
logger.warn("unnecessary --mypy argument", arg, extra="passed automatically when needed")
elif arg == "--python-version":
logger.warn("unnecessary --mypy argument", arg, extra="current --target passed as version automatically")
elif path == fixpath(arg):
logger.warn("unnecessary --mypy argument", arg, extra="path to compiled files passed automatically")
continue
args.append(arg)

if not ("--py2" in args or "-2" in args) and not self.comp.target.startswith("3"):
args.append("--py2")
if "--python-version" not in args:
args += ["--python-version", ".".join(str(v) for v in self.comp.target_info_len2)]
if "--fast-parser" not in args:
try:
import typed_ast # NOQA
Expand All @@ -523,7 +537,8 @@ def run_mypy(self, *args):
args.append("--fast-parser")

try:
run_cmd(args)
with in_mypy_path(stub_dir):
run_cmd(args)
except CalledProcessError:
raise CoconutException("failed to run MyPy command", args)

Expand Down
45 changes: 35 additions & 10 deletions coconut/command/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from coconut.highlighter import CoconutLexer

from coconut.constants import (
fixpath,
default_encoding,
main_prompt,
more_prompt,
Expand Down Expand Up @@ -76,11 +77,6 @@ def readfile(openedfile):
return str(openedfile.read())


def fixpath(path):
"""Uniformly formats a path."""
return os.path.normpath(os.path.realpath(path))


def showpath(path):
"""Formats a path for displaying."""
if logger.verbose:
Expand Down Expand Up @@ -152,7 +148,7 @@ def handles_prompt_toolkit_errors_func(self, *args, **kwargs):


@contextmanager
def handle_broken_process_pool():
def handling_broken_process_pool():
"""Handles BrokenProcessPool error."""
if sys.version_info < (3, 3):
yield
Expand Down Expand Up @@ -204,6 +200,23 @@ def run_cmd(cmd, show_output=True, raise_errs=True):
raise CoconutInternalException("cannot not show console output and not raise errors")


@contextmanager
def in_mypy_path(mypy_path):
"""Temporarily adds to MYPYPATH."""
original = os.environ.get("MYPYPATH")
if original is None:
os.environ["MYPYPATH"] = mypy_path
else:
os.environ["MYPYPATH"] += os.pathsep + mypy_path
try:
yield
finally:
if original is None:
del os.environ["MYPYPATH"]
else:
os.environ["MYPYPATH"] = original


#-----------------------------------------------------------------------------------------------------------------------
# CLASSES:
#-----------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -271,8 +284,10 @@ def __init__(self, comp=None, exit=None, path=None):
"""Creates the executor."""
self.exit = sys.exit if exit is None else exit
self.vars = self.build_vars(path)
self.lines = []
if comp is not None:
self.run(comp.headers("code"))
self.lines.append(comp.headers("module"))
self.run(comp.headers("code"), add_to_lines=False)
self.fixpickle()

def build_vars(self, path=None):
Expand Down Expand Up @@ -304,7 +319,7 @@ def handling_errors(self, all_errors_exit=False):
if all_errors_exit:
self.exit(1)

def run(self, code, use_eval=None, path=None, all_errors_exit=False):
def run(self, code, use_eval=None, path=None, all_errors_exit=False, add_to_lines=True):
"""Executes Python code."""
if use_eval is None:
run_func = interpret
Expand All @@ -314,13 +329,16 @@ def run(self, code, use_eval=None, path=None, all_errors_exit=False):
run_func = exec_func
with self.handling_errors(all_errors_exit):
if path is None:
return run_func(code, self.vars)
result = run_func(code, self.vars)
else:
use_vars = self.build_vars(path)
try:
return run_func(code, use_vars)
result = run_func(code, use_vars)
finally:
self.vars.update(use_vars)
if add_to_lines:
self.lines.append(code)
return result

def run_file(self, path, all_errors_exit=True):
"""Executes a Python file."""
Expand All @@ -330,9 +348,16 @@ def run_file(self, path, all_errors_exit=True):
with self.handling_errors(all_errors_exit):
module = imp.load_module("__main__", *found)
self.vars.update(vars(module))
self.lines.append("from " + name + " import *")
finally:
found[0].close()

def was_run_code(self, get_all=True):
"""Gets all the code that was run."""
if get_all:
self.lines = ["\n".join(self.lines)]
return self.lines[-1]


class multiprocess_wrapper(object):
"""Wrapper for a method that needs to be multiprocessed."""
Expand Down
31 changes: 25 additions & 6 deletions coconut/compiler/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
match_handle,
)
from coconut.compiler.util import (
target_info,
get_target_info,
addskip,
count_end,
paren_change,
Expand Down Expand Up @@ -386,9 +386,28 @@ def headers(self, which, usehash=None):
"""Gets a formatted header."""
return self.polish(getheader(which, self.target, usehash))

@property
def target_info(self):
"""Returns information on the current target as a version tuple."""
return target_info(self.target)
return get_target_info(self.target)

@property
def target_info_len2(self):
"""Returns target_info as a length 2 tuple."""
info = self.target_info
if not info:
return (2, 7)
elif len(info) == 1:
if info == (2,):
return (2, 7)
elif info == (3,):
return (3, 4)
else:
raise CoconutInternalException("invalid target info", info)
elif len(info) == 2:
return info
else:
return info[:2]

def should_indent(self, code):
"""Determines whether the next line should be indented."""
Expand Down Expand Up @@ -894,7 +913,7 @@ def yield_from_handle(self, tokens):
"""Processes Python 3.3 yield from."""
if len(tokens) != 1:
raise CoconutInternalException("invalid yield from tokens", tokens)
elif self.target_info() < (3, 3):
elif self.target_info < (3, 3):
return (yield_from_var + " = " + tokens[0]
+ "\nfor " + yield_item_var + " in " + yield_from_var + ":\n"
+ openindent + "yield " + yield_item_var + "\n" + closeindent)
Expand Down Expand Up @@ -1025,7 +1044,7 @@ def import_handle(self, original, loc, tokens):
paths = (imp,)
elif self.target.startswith("2"):
paths = (old_imp,)
elif not self.target or self.target_info() < version_check:
elif not self.target or self.target_info < version_check:
paths = (old_imp, imp, version_check)
else:
paths = (imp,)
Expand Down Expand Up @@ -1128,7 +1147,7 @@ def set_literal_handle(self, tokens):
raise CoconutInternalException("invalid set literal tokens", tokens)
elif len(tokens[0]) != 1:
raise CoconutInternalException("invalid set literal item", tokens[0])
elif self.target_info() < (2, 7):
elif self.target_info < (2, 7):
return "_coconut.set(" + set_to_tuple(tokens[0]) + ")"
else:
return "{" + tokens[0][0] + "}"
Expand Down Expand Up @@ -1419,7 +1438,7 @@ def check_py(self, version, name, original, loc, tokens):
"""Checks for Python-version-specific syntax."""
if len(tokens) != 1:
raise CoconutInternalException("invalid " + name + " tokens", tokens)
elif self.target_info() < target_info(version):
elif self.target_info < get_target_info(version):
raise self.make_err(CoconutTargetError, "found Python " + version + " " + name, original, loc, target=version)
else:
return tokens[0]
Expand Down
Loading

0 comments on commit 11f67aa

Please sign in to comment.