coconut-develop 3.1.0.post0.dev15__tar.gz → 3.1.0.post0.dev16__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/DOCS.md +13 -7
  2. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/PKG-INFO +2 -1
  3. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/cli.py +6 -0
  4. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/command.py +42 -26
  5. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/util.py +35 -9
  6. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/watch.py +18 -2
  7. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/compiler/compiler.py +1 -1
  8. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/compiler/util.py +3 -3
  9. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/constants.py +12 -0
  10. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/requirements.py +1 -0
  11. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/root.py +1 -1
  12. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/main_test.py +1 -0
  13. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut_develop.egg-info/SOURCES.txt +0 -1
  14. coconut-develop-3.1.0.post0.dev15/coconut/command/resources/pyrightconfig.json +0 -7
  15. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/CONTRIBUTING.md +0 -0
  16. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/FAQ.md +0 -0
  17. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/HELP.md +0 -0
  18. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/LICENSE.txt +0 -0
  19. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/MANIFEST.in +0 -0
  20. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/README.rst +0 -0
  21. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/__coconut__/__init__.py +0 -0
  22. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/__coconut__/__init__.pyi +0 -0
  23. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/__coconut__/py.typed +0 -0
  24. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/_coconut/__init__.py +0 -0
  25. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/_coconut/__init__.pyi +0 -0
  26. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/_coconut/py.typed +0 -0
  27. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/__coconut__.py +0 -0
  28. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/__coconut__.pyi +0 -0
  29. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/__init__.py +0 -0
  30. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/__init__.pyi +0 -0
  31. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/__main__.py +0 -0
  32. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/_pyparsing.py +0 -0
  33. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/api.py +0 -0
  34. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/api.pyi +0 -0
  35. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/__init__.py +0 -0
  36. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/__init__.pyi +0 -0
  37. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/command.pyi +0 -0
  38. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/mypy.py +0 -0
  39. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/command/resources/zcoconut.pth +0 -0
  40. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/compiler/__init__.py +0 -0
  41. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/compiler/grammar.py +0 -0
  42. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/compiler/header.py +0 -0
  43. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/compiler/matching.py +0 -0
  44. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/compiler/templates/header.py_template +0 -0
  45. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/convenience.py +0 -0
  46. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/convenience.pyi +0 -0
  47. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/exceptions.py +0 -0
  48. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/highlighter.py +0 -0
  49. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/icoconut/__init__.py +0 -0
  50. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/icoconut/__main__.py +0 -0
  51. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/icoconut/coconut/kernel.json +0 -0
  52. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/icoconut/coconut_py/kernel.json +0 -0
  53. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/icoconut/coconut_py2/kernel.json +0 -0
  54. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/icoconut/coconut_py3/kernel.json +0 -0
  55. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/icoconut/embed.py +0 -0
  56. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/icoconut/root.py +0 -0
  57. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/integrations.py +0 -0
  58. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/main.py +0 -0
  59. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/py.typed +0 -0
  60. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/terminal.py +0 -0
  61. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/__init__.py +0 -0
  62. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/__main__.py +0 -0
  63. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/constants_test.py +0 -0
  64. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/__init__.coco +0 -0
  65. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/__main__.coco +0 -0
  66. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/main.coco +0 -0
  67. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/primary_1.coco +0 -0
  68. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/primary_2.coco +0 -0
  69. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/specific.coco +0 -0
  70. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/suite.coco +0 -0
  71. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/tutorial.coco +0 -0
  72. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/agnostic/util.coco +0 -0
  73. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/non_strict/non_strict_test.coco +0 -0
  74. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/target_2/py2_test.coco +0 -0
  75. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/target_3/py3_test.coco +0 -0
  76. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/target_311/py311_test.coco +0 -0
  77. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/target_35/py35_test.coco +0 -0
  78. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/target_36/py36_test.coco +0 -0
  79. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/target_38/py38_test.coco +0 -0
  80. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/cocotest/target_sys/target_sys_test.coco +0 -0
  81. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/extras.coco +0 -0
  82. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/importable.coco +0 -0
  83. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/runnable.coco +0 -0
  84. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/tests/src/runner.coco +0 -0
  85. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/coconut/util.py +0 -0
  86. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/conf.py +0 -0
  87. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/pyproject.toml +0 -0
  88. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/setup.cfg +0 -0
  89. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/setup.py +0 -0
  90. {coconut-develop-3.1.0.post0.dev15 → coconut-develop-3.1.0.post0.dev16}/xontrib/coconut.py +0 -0
@@ -92,6 +92,7 @@ The full list of optional dependencies is:
92
92
  - `kernel`: lightweight subset of `jupyter` that only includes the dependencies that are strictly necessary for Coconut's [Jupyter kernel](#kernel).
93
93
  - `watch`: enables use of the `--watch` flag.
94
94
  - `mypy`: enables use of the `--mypy` flag.
95
+ - `pyright`: enables use of the `--pyright` flag.
95
96
  - `xonsh`: enables use of Coconut's [`xonsh` support](#xonsh-support).
96
97
  - `numpy`: installs everything necessary for making use of Coconut's [`numpy` integration](#numpy-integration).
97
98
  - `jupyterlab`: installs everything necessary to use [JupyterLab](https://github.com/jupyterlab/jupyterlab) with Coconut.
@@ -121,11 +122,11 @@ depth: 1
121
122
 
122
123
  ```
123
124
  coconut [-h] [--and source [dest ...]] [-v] [-t version] [-i] [-p] [-a] [-l]
124
- [--no-line-numbers] [-k] [-w] [-r] [-n] [-d] [-q] [-s] [--no-tco]
125
- [--no-wrap-types] [-c code] [--incremental] [-j processes] [-f] [--minify]
126
- [--jupyter ...] [--mypy ...] [--argv ...] [--tutorial] [--docs] [--style name]
127
- [--vi-mode] [--recursion-limit limit] [--stack-size kbs] [--site-install]
128
- [--site-uninstall] [--verbose] [--trace] [--profile]
125
+ [--no-line-numbers] [-k] [-w] [-r] [-n] [-d] [-q] [-s] [--no-tco] [--no-wrap-types]
126
+ [-c code] [-j processes] [-f] [--minify] [--jupyter ...] [--mypy ...] [--pyright]
127
+ [--argv ...] [--tutorial] [--docs] [--style name] [--vi-mode]
128
+ [--recursion-limit limit] [--stack-size kbs] [--fail-fast] [--no-cache]
129
+ [--site-install] [--site-uninstall] [--verbose] [--trace] [--profile]
129
130
  [source] [dest]
130
131
  ```
131
132
 
@@ -184,6 +185,7 @@ dest destination directory for compiled files (defaults to
184
185
  Jupyter)
185
186
  --mypy ... run MyPy on compiled Python (remaining args passed to MyPy) (implies
186
187
  --package --line-numbers)
188
+ --pyright run Pyright on compiled Python (implies --package)
187
189
  --argv ..., --args ...
188
190
  set sys.argv to source plus remaining args for use in the Coconut script
189
191
  being run
@@ -452,6 +454,10 @@ You can also run `mypy`—or any other static type checker—directly on the com
452
454
 
453
455
  To distribute your code with checkable type annotations, you'll need to include `coconut` as a dependency (though a `--no-deps` install should be fine), as installing it is necessary to make the requisite stub files available. You'll also probably want to include a [`py.typed`](https://peps.python.org/pep-0561/) file.
454
456
 
457
+ ##### Pyright Integration
458
+
459
+ Though not as well-supported as MyPy, Coconut also has built-in [Pyright](https://github.com/microsoft/pyright) support. Simply pass `--pyright` to automatically run Pyright on all compiled code. To adjust Pyright options, rather than pass them at the command-line, add your settings to the file `~/.coconut_pyrightconfig.json` (automatically generated the first time `coconut --pyright` is run).
460
+
455
461
  ##### Syntax
456
462
 
457
463
  To explicitly annotate your code with types to be checked, Coconut supports (on all Python versions):
@@ -467,7 +473,7 @@ Sometimes, MyPy will not know how to handle certain Coconut constructs, such as
467
473
 
468
474
  ##### Interpreter
469
475
 
470
- Coconut even supports `--mypy` in the interpreter, which will intelligently scan each new line of code, in the context of previous lines, for newly-introduced MyPy errors. For example:
476
+ Coconut even supports `--mypy` (though not `--pyright`) in the interpreter, which will intelligently scan each new line of code, in the context of previous lines, for newly-introduced MyPy errors. For example:
471
477
  ```coconut_pycon
472
478
  >>> a: str = count()[0]
473
479
  <string>:14: error: Incompatible types in assignment (expression has type "int", variable has type "str")
@@ -4655,7 +4661,7 @@ else:
4655
4661
 
4656
4662
  #### `reveal_type` and `reveal_locals`
4657
4663
 
4658
- When using MyPy, `reveal_type(<expr>)` will cause MyPy to print the type of `<expr>` and `reveal_locals()` will cause MyPy to print the types of the current `locals()`. At runtime, `reveal_type(x)` is always the identity function and `reveal_locals()` always returns `None`. See [the MyPy documentation](https://mypy.readthedocs.io/en/stable/common_issues.html#reveal-type) for more information.
4664
+ When using static type analysis tools integrated with Coconut such as [MyPy](#mypy-integration), `reveal_type(<expr>)` will cause MyPy to print the type of `<expr>` and `reveal_locals()` will cause MyPy to print the types of the current `locals()`. At runtime, `reveal_type(x)` is always the identity function and `reveal_locals()` always returns `None`. See [the MyPy documentation](https://mypy.readthedocs.io/en/stable/common_issues.html#reveal-type) for more information.
4659
4665
 
4660
4666
  ##### Example
4661
4667
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: coconut-develop
3
- Version: 3.1.0.post0.dev15
3
+ Version: 3.1.0.post0.dev16
4
4
  Summary: Simple, elegant, Pythonic functional programming.
5
5
  Home-page: http://coconut-lang.org
6
6
  Author: Evan Hubinger
@@ -128,6 +128,7 @@ Classifier: Typing :: Typed
128
128
  Provides-Extra: kernel
129
129
  Provides-Extra: watch
130
130
  Provides-Extra: mypy
131
+ Provides-Extra: pyright
131
132
  Provides-Extra: xonsh
132
133
  Provides-Extra: numpy
133
134
  Provides-Extra: jupyter
@@ -216,6 +216,12 @@ arguments.add_argument(
216
216
  help="run MyPy on compiled Python (remaining args passed to MyPy) (implies --package --line-numbers)",
217
217
  )
218
218
 
219
+ arguments.add_argument(
220
+ "--pyright",
221
+ action="store_true",
222
+ help="run Pyright on compiled Python (implies --package)",
223
+ )
224
+
219
225
  arguments.add_argument(
220
226
  "--argv", "--args",
221
227
  type=str,
@@ -83,8 +83,6 @@ from coconut.util import (
83
83
  first_import_time,
84
84
  )
85
85
  from coconut.command.util import (
86
- writefile,
87
- readfile,
88
86
  showpath,
89
87
  rem_encoding,
90
88
  Runner,
@@ -104,6 +102,7 @@ from coconut.command.util import (
104
102
  run_with_stack_size,
105
103
  proc_run_args,
106
104
  get_python_lib,
105
+ update_pyright_config,
107
106
  )
108
107
  from coconut.compiler.util import (
109
108
  should_indent,
@@ -128,6 +127,7 @@ class Command(object):
128
127
  display = False # corresponds to --display flag
129
128
  jobs = 0 # corresponds to --jobs flag
130
129
  mypy_args = None # corresponds to --mypy flag
130
+ pyright = False # corresponds to --pyright flag
131
131
  argv_args = None # corresponds to --argv flag
132
132
  stack_size = 0 # corresponds to --stack-size flag
133
133
  use_cache = USE_CACHE # corresponds to --no-cache flag
@@ -252,6 +252,8 @@ class Command(object):
252
252
  logger.log("Directly passed args:", original_args)
253
253
  logger.log("Parsed args:", args)
254
254
 
255
+ type_checking_arg = "--mypy" if args.mypy else "--pyright" if args.pyright else None
256
+
255
257
  # validate args and show warnings
256
258
  if args.stack_size and args.stack_size % 4 != 0:
257
259
  logger.warn("--stack-size should generally be a multiple of 4, not {stack_size} (to support 4 KB pages)".format(stack_size=args.stack_size))
@@ -259,8 +261,8 @@ class Command(object):
259
261
  logger.warn("using --mypy running with --no-line-numbers is not recommended; mypy error messages won't include Coconut line numbers")
260
262
  if args.interact and args.run:
261
263
  logger.warn("extraneous --run argument passed; --interact implies --run")
262
- if args.package and self.mypy:
263
- logger.warn("extraneous --package argument passed; --mypy implies --package")
264
+ if args.package and type_checking_arg:
265
+ logger.warn("extraneous --package argument passed; --{type_checking_arg} implies --package".format(type_checking_arg=type_checking_arg))
264
266
 
265
267
  # validate args and raise errors
266
268
  if args.line_numbers and args.no_line_numbers:
@@ -269,10 +271,10 @@ class Command(object):
269
271
  raise CoconutException("cannot --site-install and --site-uninstall simultaneously")
270
272
  if args.standalone and args.package:
271
273
  raise CoconutException("cannot compile as both --package and --standalone")
272
- if args.standalone and self.mypy:
273
- raise CoconutException("cannot compile as both --package (implied by --mypy) and --standalone")
274
- if args.no_write and self.mypy:
275
- raise CoconutException("cannot compile with --no-write when using --mypy")
274
+ if args.standalone and type_checking_arg:
275
+ raise CoconutException("cannot compile as both --package (implied by --{type_checking_arg}) and --standalone".format(type_checking_arg=type_checking_arg))
276
+ if args.no_write and type_checking_arg:
277
+ raise CoconutException("cannot compile with --no-write when using --{type_checking_arg}".format(type_checking_arg=type_checking_arg))
276
278
  for and_args in getattr(args, "and") or []:
277
279
  if len(and_args) > 2:
278
280
  raise CoconutException(
@@ -291,6 +293,7 @@ class Command(object):
291
293
  set_recursion_limit(args.recursion_limit)
292
294
  self.fail_fast = args.fail_fast
293
295
  self.display = args.display
296
+ self.pyright = args.pyright
294
297
  self.prompt.vi_mode = args.vi_mode
295
298
  if args.style is not None:
296
299
  self.prompt.set_style(args.style)
@@ -375,8 +378,8 @@ class Command(object):
375
378
  for kwargs in all_compile_path_kwargs:
376
379
  filepaths += self.compile_path(**kwargs)
377
380
 
378
- # run mypy on compiled files
379
- self.run_mypy(filepaths)
381
+ # run type checking on compiled files
382
+ self.run_type_checking(filepaths)
380
383
 
381
384
  # do extra compilation if there is any
382
385
  if extra_compile_path_kwargs:
@@ -456,7 +459,7 @@ class Command(object):
456
459
  processed_dest = dest
457
460
 
458
461
  # determine package mode
459
- if args.package or self.mypy:
462
+ if args.package or self.type_checking:
460
463
  package = True
461
464
  elif args.standalone:
462
465
  package = False
@@ -576,7 +579,7 @@ class Command(object):
576
579
  def compile(self, codepath, destpath=None, package=False, run=False, force=False, show_unchanged=True, handling_exceptions_kwargs={}, callback=None):
577
580
  """Compile a source Coconut file to a destination Python file."""
578
581
  with univ_open(codepath, "r") as opened:
579
- code = readfile(opened)
582
+ code = opened.read()
580
583
 
581
584
  package_level = -1
582
585
  if destpath is not None:
@@ -607,7 +610,7 @@ class Command(object):
607
610
  logger.show_tabulated("Compiled", showpath(codepath), "without writing to file.")
608
611
  else:
609
612
  with univ_open(destpath, "w") as opened:
610
- writefile(opened, compiled)
613
+ opened.write(compiled)
611
614
  logger.show_tabulated("Compiled to", showpath(destpath), ".")
612
615
  if self.display:
613
616
  logger.print(compiled)
@@ -657,7 +660,7 @@ class Command(object):
657
660
  filepath = os.path.join(dirpath, "__coconut__.py")
658
661
  try:
659
662
  with univ_open(filepath, "w") as opened:
660
- writefile(opened, self.comp.getheader("__coconut__"))
663
+ opened.write(self.comp.getheader("__coconut__"))
661
664
  except OSError:
662
665
  logger.log_exc()
663
666
  if retries_left <= 0:
@@ -792,7 +795,7 @@ class Command(object):
792
795
  """Determine if a file has the hash of the code."""
793
796
  if destpath is not None and os.path.isfile(destpath):
794
797
  with univ_open(destpath, "r") as opened:
795
- compiled = readfile(opened)
798
+ compiled = opened.read()
796
799
  hashash = gethash(compiled)
797
800
  if hashash is not None:
798
801
  newhash = self.comp.genhash(code, package_level)
@@ -880,7 +883,7 @@ class Command(object):
880
883
  logger.print(compiled)
881
884
 
882
885
  if path is None: # header is not included
883
- if not self.mypy:
886
+ if not self.type_checking:
884
887
  no_str_code = self.comp.remove_strs(compiled)
885
888
  if no_str_code is not None:
886
889
  result = mypy_builtin_regex.search(no_str_code)
@@ -892,7 +895,7 @@ class Command(object):
892
895
 
893
896
  self.runner.run(compiled, use_eval=use_eval, path=path, all_errors_exit=path is not None)
894
897
 
895
- self.run_mypy(code=self.runner.was_run_code())
898
+ self.run_type_checking(code=self.runner.was_run_code())
896
899
 
897
900
  def execute_file(self, destpath, **kwargs):
898
901
  """Execute compiled file."""
@@ -912,15 +915,20 @@ class Command(object):
912
915
 
913
916
  # set up runner
914
917
  if self.runner is None:
915
- self.runner = Runner(self.comp, exit=self.exit_runner, store=self.mypy)
918
+ self.runner = Runner(self.comp, exit=self.exit_runner, store=self.type_checking)
916
919
 
917
920
  # pass runner to prompt
918
921
  self.prompt.set_runner(self.runner)
919
922
 
920
923
  @property
921
- def mypy(self):
922
- """Whether using MyPy or not."""
923
- return self.mypy_args is not None
924
+ def type_checking(self):
925
+ """Whether using a static type-checker or not."""
926
+ return self.mypy_args is not None or self.pyright
927
+
928
+ @property
929
+ def type_checking_version(self):
930
+ """What version of Python to type check against."""
931
+ return ver_tuple_to_str(get_target_info_smart(self.comp.target, mode="highest"))
924
932
 
925
933
  def set_mypy_args(self, mypy_args=None):
926
934
  """Set MyPy arguments."""
@@ -940,7 +948,7 @@ class Command(object):
940
948
  if not any(arg.startswith("--python-version") for arg in self.mypy_args):
941
949
  self.mypy_args += [
942
950
  "--python-version",
943
- ver_tuple_to_str(get_target_info_smart(self.comp.target, mode="highest")),
951
+ self.type_checking_version,
944
952
  ]
945
953
 
946
954
  if not any(arg.startswith("--python-executable") for arg in self.mypy_args):
@@ -960,9 +968,9 @@ class Command(object):
960
968
  logger.log("MyPy args:", self.mypy_args)
961
969
  self.mypy_errs = []
962
970
 
963
- def run_mypy(self, paths=(), code=None):
964
- """Run MyPy with arguments."""
965
- if self.mypy:
971
+ def run_type_checking(self, paths=(), code=None):
972
+ """Run type-checking on the given paths / code."""
973
+ if self.mypy_args is not None:
966
974
  set_mypy_path()
967
975
  from coconut.command.mypy import mypy_run
968
976
  args = list(paths) + self.mypy_args
@@ -987,6 +995,14 @@ class Command(object):
987
995
  if code is not None: # interpreter
988
996
  logger.printerr(line)
989
997
  self.mypy_errs.append(line)
998
+ if self.pyright:
999
+ config_file = update_pyright_config()
1000
+ if code is not None:
1001
+ logger.warn("--pyright only works on files, not code snippets or at the interpreter")
1002
+ if paths:
1003
+ from pyright import main
1004
+ args = ["--project", config_file, "--pythonversion", self.type_checking_version] + list(paths)
1005
+ main(args)
990
1006
 
991
1007
  def run_silent_cmd(self, *args):
992
1008
  """Same as run_cmd$(show_output=logger.verbose)."""
@@ -1157,7 +1173,7 @@ class Command(object):
1157
1173
  writedir = os.path.join(dest, os.path.relpath(dirpath, src))
1158
1174
 
1159
1175
  def inner_callback(path):
1160
- self.run_mypy([path])
1176
+ self.run_type_checking([path])
1161
1177
  callback()
1162
1178
  self.compile_path(
1163
1179
  path,
@@ -24,6 +24,7 @@ import os
24
24
  import subprocess
25
25
  import shutil
26
26
  import threading
27
+ import json
27
28
  from select import select
28
29
  from contextlib import contextmanager
29
30
  from functools import partial
@@ -50,6 +51,7 @@ from coconut.util import (
50
51
  get_encoding,
51
52
  get_clock_time,
52
53
  assert_remove_prefix,
54
+ univ_open,
53
55
  )
54
56
  from coconut.constants import (
55
57
  WINDOWS,
@@ -88,6 +90,9 @@ from coconut.constants import (
88
90
  high_proc_prio,
89
91
  call_timeout,
90
92
  use_fancy_call_output,
93
+ extra_pyright_args,
94
+ pyright_config_file,
95
+ tabideal,
91
96
  )
92
97
 
93
98
  if PY26:
@@ -148,17 +153,23 @@ except ImportError:
148
153
  # -----------------------------------------------------------------------------------------------------------------------
149
154
 
150
155
 
151
- def writefile(openedfile, newcontents):
152
- """Set the contents of a file."""
156
+ def writefile(openedfile, newcontents, in_json=False, **kwargs):
157
+ """Set the entire contents of a file regardless of current position."""
153
158
  openedfile.seek(0)
154
159
  openedfile.truncate()
155
- openedfile.write(newcontents)
160
+ if in_json:
161
+ json.dump(newcontents, openedfile, **kwargs)
162
+ else:
163
+ openedfile.write(newcontents, **kwargs)
156
164
 
157
165
 
158
- def readfile(openedfile):
159
- """Read the contents of a file."""
166
+ def readfile(openedfile, in_json=False, **kwargs):
167
+ """Read the entire contents of a file regardless of current position."""
160
168
  openedfile.seek(0)
161
- return str(openedfile.read())
169
+ if in_json:
170
+ return json.load(openedfile, **kwargs)
171
+ else:
172
+ return str(openedfile.read(**kwargs))
162
173
 
163
174
 
164
175
  def open_website(url):
@@ -450,8 +461,8 @@ def symlink(link_to, link_from):
450
461
  shutil.copytree(link_to, link_from)
451
462
 
452
463
 
453
- def install_mypy_stubs():
454
- """Properly symlink mypy stub files."""
464
+ def install_stubs():
465
+ """Properly symlink stub files for type-checking purposes."""
455
466
  # unlink stub_dirs so we know rm_dir_or_link won't clear them
456
467
  for stub_name in stub_dir_names:
457
468
  unlink(os.path.join(base_stub_dir, stub_name))
@@ -480,7 +491,7 @@ def set_env_var(name, value):
480
491
  def set_mypy_path():
481
492
  """Put Coconut stubs in MYPYPATH."""
482
493
  # mypy complains about the path if we don't use / over \
483
- install_dir = install_mypy_stubs().replace(os.sep, "/")
494
+ install_dir = install_stubs().replace(os.sep, "/")
484
495
  original = os.getenv(mypy_path_env_var)
485
496
  if original is None:
486
497
  new_mypy_path = install_dir
@@ -494,6 +505,21 @@ def set_mypy_path():
494
505
  return install_dir
495
506
 
496
507
 
508
+ def update_pyright_config(python_version=None):
509
+ """Save an updated pyrightconfig.json."""
510
+ update_existing = os.path.exists(pyright_config_file)
511
+ with univ_open(pyright_config_file, "r+" if update_existing else "w") as config_file:
512
+ if update_existing:
513
+ config = readfile(config_file, in_json=True)
514
+ else:
515
+ config = extra_pyright_args.copy()
516
+ config["extraPaths"] = [install_stubs()]
517
+ if python_version is not None:
518
+ config["pythonVersion"] = python_version
519
+ writefile(config_file, config, in_json=True, indent=tabideal)
520
+ return pyright_config_file
521
+
522
+
497
523
  def is_empty_pipe(pipe, default=None):
498
524
  """Determine if the given pipe file object is empty."""
499
525
  if pipe.closed:
@@ -21,6 +21,8 @@ from coconut.root import * # NOQA
21
21
 
22
22
  import sys
23
23
 
24
+ from functools import partial
25
+
24
26
  from coconut.terminal import logger
25
27
  from coconut.exceptions import CoconutException
26
28
 
@@ -48,13 +50,27 @@ class RecompilationWatcher(FileSystemEventHandler):
48
50
  self.args = args
49
51
  self.kwargs = kwargs
50
52
  self.saw = set()
53
+ self.saw_twice = set()
51
54
 
52
55
  def on_modified(self, event):
53
56
  """Handle a file modified event."""
54
- path = event.src_path
57
+ self.handle(event.src_path)
58
+
59
+ def handle(self, path):
60
+ """Handle a potential recompilation event for the given path."""
55
61
  if path in self.saw:
56
62
  logger.log("Skipping watch event for: " + repr(path) + "\n\t(currently compiling: " + repr(self.saw) + ")")
63
+ self.saw_twice.add(path)
57
64
  else:
58
65
  logger.log("Handling watch event for: " + repr(path) + "\n\t(currently compiling: " + repr(self.saw) + ")")
59
66
  self.saw.add(path)
60
- self.recompile(path, callback=lambda: self.saw.discard(path), *self.args, **self.kwargs)
67
+ self.saw_twice.discard(path)
68
+ self.recompile(path, callback=partial(self.callback, path), *self.args, **self.kwargs)
69
+
70
+ def callback(self, path):
71
+ """Callback for after recompiling the given path."""
72
+ self.saw.discard(path)
73
+ if path in self.saw_twice:
74
+ logger.log("Submitting deferred watch event for: " + repr(path) + "\n\t(currently deferred: " + repr(self.saw_twice) + ")")
75
+ self.saw_twice.discard(path)
76
+ self.handle(path)
@@ -5209,7 +5209,7 @@ class {protocol_var}({tokens}, _coconut.typing.Protocol): pass
5209
5209
  self.streamline(self.file_parser, force=streamline)
5210
5210
  self.streamline(self.eval_parser, force=streamline)
5211
5211
  if enable_incremental_mode:
5212
- enable_incremental_parsing()
5212
+ enable_incremental_parsing(reason="explicit warm_up call")
5213
5213
 
5214
5214
 
5215
5215
  # end: ENDPOINTS
@@ -1035,7 +1035,7 @@ def get_highest_parse_loc(original):
1035
1035
  return highest_loc
1036
1036
 
1037
1037
 
1038
- def enable_incremental_parsing():
1038
+ def enable_incremental_parsing(reason="explicit enable_incremental_parsing call"):
1039
1039
  """Enable incremental parsing mode where prefix/suffix parses are reused."""
1040
1040
  if not SUPPORTS_INCREMENTAL:
1041
1041
  return False
@@ -1051,7 +1051,7 @@ def enable_incremental_parsing():
1051
1051
  )
1052
1052
  except ImportError as err:
1053
1053
  raise CoconutException(str(err))
1054
- logger.log("Incremental parsing mode enabled.")
1054
+ logger.log("Incremental parsing mode enabled due to {reason}.".format(reason=reason))
1055
1055
  return True
1056
1056
 
1057
1057
 
@@ -1199,7 +1199,7 @@ def load_cache_for(inputstring, codepath):
1199
1199
  incremental_enabled = True
1200
1200
  incremental_info = "using incremental parsing mode since it was already enabled"
1201
1201
  elif len(inputstring) < disable_incremental_for_len:
1202
- incremental_enabled = enable_incremental_parsing()
1202
+ incremental_enabled = enable_incremental_parsing(reason="input length")
1203
1203
  if incremental_enabled:
1204
1204
  incremental_info = "incremental parsing mode enabled due to len == {input_len} < {max_len}".format(
1205
1205
  input_len=len(inputstring),
@@ -670,6 +670,8 @@ stub_dir_names = (
670
670
  )
671
671
  installed_stub_dir = os.path.join(coconut_home, ".coconut_stubs")
672
672
 
673
+ pyright_config_file = os.path.join(coconut_home, ".coconut_pyrightconfig.json")
674
+
673
675
  watch_interval = .1 # seconds
674
676
 
675
677
  info_tabulation = 18 # offset for tabulated info messages
@@ -722,6 +724,10 @@ mypy_non_err_infixes = (
722
724
  ": note: ",
723
725
  )
724
726
 
727
+ extra_pyright_args = {
728
+ "reportPossiblyUnboundVariable": False,
729
+ }
730
+
725
731
  oserror_retcode = 127
726
732
 
727
733
  kilobyte = 1024
@@ -985,6 +991,11 @@ all_reqs = {
985
991
  "types-backports",
986
992
  ("typing", "py<35"),
987
993
  ),
994
+ "pyright": (
995
+ "pyright",
996
+ "types-backports",
997
+ ("typing", "py<35"),
998
+ ),
988
999
  "watch": (
989
1000
  "watchdog",
990
1001
  ),
@@ -1041,6 +1052,7 @@ unpinned_min_versions = {
1041
1052
  "myst-parser": (3,),
1042
1053
  "sphinx": (7,),
1043
1054
  "mypy[python2]": (1, 10),
1055
+ "pyright": (1, 1),
1044
1056
  ("jupyter-console", "py37"): (6, 6),
1045
1057
  ("typing", "py<35"): (3, 10),
1046
1058
  ("typing_extensions", "py>=38"): (4, 11),
@@ -223,6 +223,7 @@ extras = {
223
223
  "kernel": get_reqs("kernel"),
224
224
  "watch": get_reqs("watch"),
225
225
  "mypy": get_reqs("mypy"),
226
+ "pyright": get_reqs("pyright"),
226
227
  "xonsh": get_reqs("xonsh"),
227
228
  "numpy": get_reqs("numpy"),
228
229
  }
@@ -26,7 +26,7 @@ import sys as _coconut_sys
26
26
  VERSION = "3.1.0"
27
27
  VERSION_NAME = None
28
28
  # False for release, int >= 1 for develop
29
- DEVELOP = 15
29
+ DEVELOP = 16
30
30
  ALPHA = False # for pre releases rather than post releases
31
31
 
32
32
  assert DEVELOP is False or DEVELOP >= 1, "DEVELOP must be False or an int >= 1"
@@ -182,6 +182,7 @@ ignore_last_lines_with = (
182
182
  " assert_raises(",
183
183
  "Populating initial parsing cache",
184
184
  "_coconut.warnings.warn(",
185
+ ": SyntaxWarning: invalid escape sequence",
185
186
  )
186
187
 
187
188
  kernel_installation_msg = (
@@ -43,7 +43,6 @@ coconut/command/command.pyi
43
43
  coconut/command/mypy.py
44
44
  coconut/command/util.py
45
45
  coconut/command/watch.py
46
- coconut/command/resources/pyrightconfig.json
47
46
  coconut/command/resources/zcoconut.pth
48
47
  coconut/compiler/__init__.py
49
48
  coconut/compiler/compiler.py
@@ -1,7 +0,0 @@
1
- {
2
- "extraPaths": [
3
- "C://Users/evanj/.coconut_stubs"
4
- ],
5
- "pythonVersion": "3.11",
6
- "reportPossiblyUnboundVariable": false
7
- }