Skip to content

Commit

Permalink
Improve pyright support
Browse files Browse the repository at this point in the history
  • Loading branch information
evhub committed Jun 7, 2024
1 parent 1d682b7 commit 81286d9
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 25 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ After you've tested your changes locally, you'll want to add more permanent test
1. Preparation:
1. Run `make check-reqs` and update dependencies as necessary
2. Run `sudo make format`
3. Make sure `make test`, `make test-py2`, and `make test-easter-eggs` are passing
3. Make sure `make test`, `make test-pyright`, and `make test-easter-eggs` are passing
4. Ensure that `coconut --watch` can successfully compile files when they're modified
5. Check changes in [`compiled-cocotest`](https://github.com/evhub/compiled-cocotest), [`pyprover`](https://github.com/evhub/pyprover), and [`coconut-prelude`](https://github.com/evhub/coconut-prelude)
6. Check [Codebeat](https://codebeat.co/a/evhub/projects) and [LGTM](https://lgtm.com/dashboard) for `coconut` and `compiled-cocotest`
Expand Down
44 changes: 25 additions & 19 deletions coconut/command/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,6 @@ def execute_args(self, args, interact=True, original_args=None):
set_recursion_limit(args.recursion_limit)
self.fail_fast = args.fail_fast
self.display = args.display
self.pyright = args.pyright
self.prompt.vi_mode = args.vi_mode
if args.style is not None:
self.prompt.set_style(args.style)
Expand Down Expand Up @@ -344,9 +343,11 @@ def execute_args(self, args, interact=True, original_args=None):
),
)

# process mypy args and print timing info (must come after compiler setup)
# process mypy + pyright args and print timing info (must come after compiler setup)
if args.mypy is not None:
self.set_mypy_args(args.mypy)
if args.pyright:
self.enable_pyright()
logger.log_compiler_stats(self.comp)

# do compilation, keeping track of compiled filepaths
Expand Down Expand Up @@ -697,15 +698,15 @@ def register_exit_code(self, code=1, errmsg=None, err=None):
errmsg = format_error(err)
else:
errmsg = err.__class__.__name__
if errmsg is not None:
if self.errmsg is None:
self.errmsg = errmsg
elif errmsg not in self.errmsg:
if logger.verbose:
self.errmsg += "\nAnd error: " + errmsg
else:
self.errmsg += "; " + errmsg
if code is not None:
if code:
if errmsg is not None:
if self.errmsg is None:
self.errmsg = errmsg
elif errmsg not in self.errmsg:
if logger.verbose:
self.errmsg += "\nAnd error: " + errmsg
else:
self.errmsg += "; " + errmsg
self.exit_code = code or self.exit_code

@contextmanager
Expand Down Expand Up @@ -888,7 +889,7 @@ def execute(self, compiled=None, path=None, use_eval=False, allow_show=True):
if no_str_code is not None:
result = mypy_builtin_regex.search(no_str_code)
if result:
logger.warn("found mypy-only built-in " + repr(result.group(0)) + "; pass --mypy to use mypy-only built-ins at the interpreter")
logger.warn("found type-checking-only built-in " + repr(result.group(0)) + "; pass --mypy to use such built-ins at the interpreter")

else: # header is included
compiled = rem_encoding(compiled)
Expand Down Expand Up @@ -935,10 +936,11 @@ def set_mypy_args(self, mypy_args=None):
if mypy_args is None:
self.mypy_args = None

elif mypy_install_arg in mypy_args:
stub_dir = set_mypy_path()

if mypy_install_arg in mypy_args:
if mypy_args != [mypy_install_arg]:
raise CoconutException("'--mypy install' cannot be used alongside other --mypy arguments")
stub_dir = set_mypy_path()
logger.show_sig("Successfully installed MyPy stubs into " + repr(stub_dir))
self.mypy_args = None

Expand Down Expand Up @@ -968,10 +970,15 @@ def set_mypy_args(self, mypy_args=None):
logger.log("MyPy args:", self.mypy_args)
self.mypy_errs = []

def enable_pyright(self):
"""Enable the use of Pyright for type-checking."""
update_pyright_config()
self.pyright = True

def run_type_checking(self, paths=(), code=None):
"""Run type-checking on the given paths / code."""
if self.mypy_args is not None:
set_mypy_path()
set_mypy_path(ensure_stubs=False)
from coconut.command.mypy import mypy_run
args = list(paths) + self.mypy_args
if code is not None: # interpreter
Expand All @@ -996,9 +1003,8 @@ def run_type_checking(self, paths=(), code=None):
logger.printerr(line)
self.mypy_errs.append(line)
if self.pyright:
config_file = update_pyright_config()
if code is not None:
logger.warn("--pyright only works on files, not code snippets or at the interpreter")
logger.warn("--pyright only works on files, not code snippets or at the interpreter (use --mypy instead)")
if paths:
try:
from pyright import main
Expand All @@ -1007,8 +1013,8 @@ def run_type_checking(self, paths=(), code=None):
"coconut --pyright requires Pyright",
extra="run '{python} -m pip install coconut[pyright]' to fix".format(python=sys.executable),
)
args = ["--project", config_file, "--pythonversion", self.type_checking_version] + list(paths)
main(args)
args = ["--project", pyright_config_file, "--pythonversion", self.type_checking_version] + list(paths)
self.register_exit_code(main(args), errmsg="Pyright error")

def run_silent_cmd(self, *args):
"""Same as run_cmd$(show_output=logger.verbose)."""
Expand Down
6 changes: 4 additions & 2 deletions coconut/command/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,12 @@ def set_env_var(name, value):
os.environ[py_str(name)] = py_str(value)


def set_mypy_path():
def set_mypy_path(ensure_stubs=True):
"""Put Coconut stubs in MYPYPATH."""
if ensure_stubs:
install_stubs()
# mypy complains about the path if we don't use / over \
install_dir = install_stubs().replace(os.sep, "/")
install_dir = installed_stub_dir.replace(os.sep, "/")
original = os.getenv(mypy_path_env_var)
if original is None:
new_mypy_path = install_dir
Expand Down
5 changes: 3 additions & 2 deletions coconut/tests/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,13 @@ def main(args=None):

# compile everything
print("Compiling Coconut test suite with args %r and agnostic_target=%r." % (args, agnostic_target))
type_checking = "--mypy" in args or "--pyright" in args
comp_all(
args,
agnostic_target=agnostic_target,
expect_retcode=0 if "--mypy" not in args else None,
expect_retcode=0 if not type_checking else None,
check_errors="--verbose" not in args,
ignore_output=WINDOWS and "--mypy" not in args,
ignore_output=WINDOWS and not type_checking,
)


Expand Down
2 changes: 2 additions & 0 deletions coconut/tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ def pexpect(p, out):
ignore_error_lines_with = (
# ignore SyntaxWarnings containing assert_raises or raise
"raise",
# ignore Pyright errors
" - error: ",
)

mypy_snip = "a: str = count()[0]"
Expand Down
2 changes: 1 addition & 1 deletion coconut/tests/src/cocotest/agnostic/primary_2.coco
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ def primary_test_2() -> bool:
"{x}"
""" == '\n"2"\n'
assert f"\{1}" == "\\1"
assert f''' '{1}' ''' == " 1 "
assert f''' '{1}' ''' == " '1' "

with process_map.multiple_sequential_calls(): # type: ignore
assert map((+), range(3), range(4)$[:-1], strict=True) |> list == [0, 2, 4] == process_map((+), range(3), range(4)$[:-1], strict=True) |> list # type: ignore
Expand Down

0 comments on commit 81286d9

Please sign in to comment.