diff --git a/.efrocachemap b/.efrocachemap
index 56d3fb66..6cf03f6d 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -4068,26 +4068,26 @@
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
- "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "8624f0d3fa5414204d138a8476e9e460",
- "build/prefab/full/linux_arm64_gui/release/ballisticakit": "2587621d0c3048ef54bc4bb16d89f481",
- "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "05fae5b1cd78420264b47845a3906878",
- "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "54630e134d422ed010f66cfade0a7039",
- "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "55a876ca75282829290734a6ac66317a",
- "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "2a52aa57bd46c9fd9d3b775932a4cd2f",
- "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "4e6545a90d26c03c27813da58b478190",
- "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "b3ba73ebad2f3a0b256d85b14e97cef5",
- "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "98d9cfb5f00591c868b9ccbee52fa9e5",
- "build/prefab/full/mac_arm64_gui/release/ballisticakit": "a29c7ef8e1ab1152bbb1cc19c8d618e6",
- "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "b06f66e40e56760b1c4e6219d69f4d0f",
- "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "809817f1aad7de3560b09b76d3995120",
- "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "7e26218e4ed4fb7e316b7e1faee7aa5a",
- "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "e8059a5654ba9a52e0fd59e5f8802fbc",
- "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "2649fb0d26b27025da149be404369505",
- "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "9378675f3ca191b8e5562017993232e9",
- "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "318110d18dc080bbe8ca0bebf4243e3f",
- "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "66d49b0c135475f76056849bfc9259fd",
- "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "4b8fe7d5454d1dc3383ecba3a6f75d13",
- "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "a87c9018c9846a27596012b6689ddbd2",
+ "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "2668b413da2d1dd597a6a6b8c6ae9ee8",
+ "build/prefab/full/linux_arm64_gui/release/ballisticakit": "5d38798c383cae78c227c427ae967281",
+ "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "0df69387ebe2fb149694a267a1df4c24",
+ "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "153abebe70483d17d933127e894908c4",
+ "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "fd6768fe1167b8e24db5eb9e33360456",
+ "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "8377309f0d570de541e9210752463bab",
+ "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "b4b774fef02d72f58f8083430cbc8334",
+ "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "9b100c7bf923a8f01de1b5984f62e7e5",
+ "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "ac5ecfa5b0e10bcc0d333875bfff9d29",
+ "build/prefab/full/mac_arm64_gui/release/ballisticakit": "241d315d379eb10ec7c2c7ccc8efa99e",
+ "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "9d57aaf4d56398e67695659eedce569c",
+ "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "d22fdee9f1355dd8965f56a97518ad85",
+ "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "b85955e00c3a076af273849fd436b18c",
+ "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a044700e51b426cd333ab32308bfc033",
+ "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "e4bcb7821639ffb7e5b0616d509d3c3d",
+ "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "91a3fcefaf965260efb388f4477c8ce3",
+ "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "4a54dbbe24033a862a2dac3eb76f98b3",
+ "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "c82081e53a00d198137c934efae1ed72",
+ "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "d8ee381eafbca03eee21e1218935f499",
+ "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "f6e6fc30a1d2a3ccb2d5f43bf91c4402",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "85ba4e81a1f7ae2cff4b1355eb49904f",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "498921f7eb2afd327d4b900cb70e31f9",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "85ba4e81a1f7ae2cff4b1355eb49904f",
@@ -4104,14 +4104,14 @@
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "0ab638b6602610bdaf432e3cc2464080",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "92394eb19387c363471ce134ac9e6a1b",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "0ab638b6602610bdaf432e3cc2464080",
- "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "496f928d8cb2b2d1098c43c708d3aa85",
- "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "f410fb4c2404475130e1a293e9dd6619",
- "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "9326d4bc4859604e48c7f7e673880f1a",
- "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "3a61d82f6d9a2f6fbda245d7cdab1bbd",
- "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "95052b835c2bf55292f1982a1be2e54b",
- "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "82265f3b1c5a4cbb44369ce37ed76ebd",
- "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "47bd30d45ba7b779488e0435f0492dc1",
- "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "4c049db7c0a8311852f742083e8df3ae",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "0016db9bd4fbf158d19f5a6e84aa2f74",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "40c9f4c7076ef9013dde9afd05d89b95",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "4e74f1959b833486aa1cee0affa1aaef",
+ "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "4e39a9a8222a683aa074a0698c26c498",
+ "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "9509a8782beb8fd0fc477d0afe3cc6c0",
+ "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "091fd49e9c75b202b4f481b65f91a100",
+ "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "87567923e411e713f82429f56abd9d84",
+ "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "5e6707e7b299474ae4a43a1df2919a55",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "eeddad968b176000e31c65be6206a2bc",
diff --git a/.gitignore b/.gitignore
index d5e260ad..f8268232 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@ local.properties
.mypy_cache
.pytest_cache
.mypy.ini
+.pyrightconfig.json
.pycheckers
.flycheck-dir-locals.el
.pylintrc
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index 1573004c..535342e7 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -2385,6 +2385,7 @@
pyobjc
pyoffs
pypaths
+ pyrightconfig
pysitedir
pysources
pytest
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c98b385c..69f2c519 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-### 1.7.25 (build 21204, api 8, 2023-07-28)
+### 1.7.25 (build 21206, api 8, 2023-07-29)
- `getconfig` and `setconfig` in `efrotools` are now `getprojectconfig` and
`setprojectconfig` (to reflect the file name changes that happened in 1.7.20).
@@ -47,7 +47,7 @@
ourselves inside a standalone binary, is called 'monolithic'. To build and run
Ballistica in modular form, you can do `make cmake-modular` or `make
cmake-modular-server`. This should make it easier to use certain things like
- Python debuggers with Ballistica. While I expect most builds of the game to
+ Python debuggers with Ballistica. While I expect most builds of the engine to
remain monolithic, this may become the default for certain situations such as
server builds or possibly Linux builds if it seems beneficial. We'll see.
Modular mode should work on Linux and Mac currently; other platforms remain
diff --git a/Makefile b/Makefile
index cd5af619..9fc5eb31 100644
--- a/Makefile
+++ b/Makefile
@@ -37,8 +37,9 @@ endif
# Prereq targets that should be safe to run anytime; even if project-files
# are out of date.
-PREREQS_SAFE = .cache/checkenv .dir-locals.el .mypy.ini .pycheckers .pylintrc \
- .style.yapf .clang-format ballisticakit-cmake/.clang-format .editorconfig
+PREREQS_SAFE = .cache/checkenv .dir-locals.el .mypy.ini .pyrightconfig.json \
+ .pycheckers .pylintrc .style.yapf .clang-format \
+ ballisticakit-cmake/.clang-format .editorconfig
# Prereq targets that may break if the project needs updating should go here.
# An example is compile-command-databases; these might try to run cmake and
@@ -798,6 +799,10 @@ dmypy: py_check_prereqs
dmypy-stop: py_check_prereqs
@tools/pcommand dmypy -stop
+# Run Pyright checks on all Python code.
+pyright: py_check_prereqs
+ @tools/pcommand pyright
+
# Run PyCharm checks on all Python code.
pycharm: py_check_prereqs
@tools/pcommand pycharm
@@ -1188,6 +1193,9 @@ ENV_SRC = tools/pcommand tools/batools/build.py
.mypy.ini: config/toolconfigsrc/mypy.ini $(TOOL_CFG_SRC)
@$(TOOL_CFG_INST) $< $@
+.pyrightconfig.json: config/toolconfigsrc/pyrightconfig.json $(TOOL_CFG_SRC)
+ @$(TOOL_CFG_INST) $< $@
+
.pycheckers: config/toolconfigsrc/pycheckers $(TOOL_CFG_SRC)
@$(TOOL_CFG_INST) $< $@
diff --git a/ballisticakit-cmake/.idea/dictionaries/ericf.xml b/ballisticakit-cmake/.idea/dictionaries/ericf.xml
index 8a6af652..5d3c5eae 100644
--- a/ballisticakit-cmake/.idea/dictionaries/ericf.xml
+++ b/ballisticakit-cmake/.idea/dictionaries/ericf.xml
@@ -1395,6 +1395,7 @@
pymodulenames
pyobj
pyobjs
+ pyrightconfig
pysitedir
pythondevmode
pythonenumsmodule
diff --git a/config/spinoffconfig.py b/config/spinoffconfig.py
index 79201a04..00d0f51e 100644
--- a/config/spinoffconfig.py
+++ b/config/spinoffconfig.py
@@ -217,6 +217,7 @@ ctx.no_filter_file_names = {
# ELSE files with these extensions WILL be filtered.
ctx.filter_file_extensions = {
'.py',
+ '.pyi',
'.md',
'.cpp',
'.cc',
diff --git a/config/toolconfigsrc/pyrightconfig.json b/config/toolconfigsrc/pyrightconfig.json
new file mode 100644
index 00000000..4a4f9044
--- /dev/null
+++ b/config/toolconfigsrc/pyrightconfig.json
@@ -0,0 +1,9 @@
+{
+ "include": [
+ "tools"
+ ],
+ "typeCheckingMode": "basic",
+ "reportMissingTypeStubs": true,
+ "stubPath": "src/stubs",
+ "pythonPlatform": "Linux"
+}
diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py
index 3a005a6e..95e1b4b7 100644
--- a/src/assets/ba_data/python/baenv.py
+++ b/src/assets/ba_data/python/baenv.py
@@ -50,7 +50,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be
# using.
-TARGET_BALLISTICA_BUILD = 21204
+TARGET_BALLISTICA_BUILD = 21206
TARGET_BALLISTICA_VERSION = '1.7.25'
diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc
index fc428350..5de4aa6e 100644
--- a/src/ballistica/shared/ballistica.cc
+++ b/src/ballistica/shared/ballistica.cc
@@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica {
// These are set automatically via script; don't modify them here.
-const int kEngineBuildNumber = 21204;
+const int kEngineBuildNumber = 21206;
const char* kEngineVersion = "1.7.25";
#if BA_MONOLITHIC_BUILD
diff --git a/src/ballistica/shared/python/python_command.cc b/src/ballistica/shared/python/python_command.cc
index 04d82510..ab04999f 100644
--- a/src/ballistica/shared/python/python_command.cc
+++ b/src/ballistica/shared/python/python_command.cc
@@ -8,8 +8,9 @@
// Save/restore current command for logging/etc.
// this isn't exception-safe, but we should never let
-// exceptions bubble up through python api calls anyway
+// exceptions bubble up through Python api calls anyway
// or we'll have bigger problems on our hands.
+// FIXME: What about thread safety? Seems like this isn't.
#define PUSH_PYCOMMAND(OBJ) \
PythonCommand* prev_pycmd = current_command_; \
current_command_ = OBJ
@@ -180,11 +181,8 @@ auto PythonCommand::Eval(bool print_errors, PyObject* globals, PyObject* locals)
.Get();
}
-#pragma clang diagnostic push
-#pragma ide diagnostic ignored "RedundantCast"
assert(PyDict_Check(globals));
assert(PyDict_Check(locals));
-#pragma clang diagnostic pop
if (!eval_code_obj_.Get()) {
CompileForEval(print_errors);
diff --git a/src/ballistica/shared/python/python_command.h b/src/ballistica/shared/python/python_command.h
index f3a84095..a0a34704 100644
--- a/src/ballistica/shared/python/python_command.h
+++ b/src/ballistica/shared/python/python_command.h
@@ -15,11 +15,11 @@ namespace ballistica {
// Note to self: Originally I though I'd be using this in a lot of places,
// so I added the ability to compile once and run repeatedly, quietly
// capture output instead of printing it, etc. Now, however, its usage is
-// pretty much limited to a few places such as handling stdin and the
-// in-app console. (Most places it is much cleaner to work with proper
-// python modules and just interact with PyObject* refs to them) I should
-// look and see if python's default high level calls would suffice for these
-// purposes and potentially kill this off.
+// pretty much limited to a few places such as handling stdin and the in-app
+// console. Most places it is much cleaner to work with proper python
+// modules and just interact with PyObject* refs to them. I should look and
+// see if Python's default high level calls would suffice for these purposes
+// and potentially kill this off.
class PythonCommand {
public:
PythonCommand();
@@ -58,7 +58,7 @@ class PythonCommand {
void CompileForEval(bool print_errors);
private:
- bool dead_ = false;
+ bool dead_{};
PythonRef file_code_obj_;
PythonRef eval_code_obj_;
std::string command_;
diff --git a/src/stubs/ansiwrap.pyi b/src/stubs/ansiwrap.pyi
new file mode 100644
index 00000000..edbb4bff
--- /dev/null
+++ b/src/stubs/ansiwrap.pyi
@@ -0,0 +1,5 @@
+# Everything resolves to Any.
+from typing import Any
+
+def __getattr__(name) -> Any:
+ ...
diff --git a/src/stubs/astroid/__init__.pyi b/src/stubs/astroid/__init__.pyi
new file mode 100644
index 00000000..edbb4bff
--- /dev/null
+++ b/src/stubs/astroid/__init__.pyi
@@ -0,0 +1,5 @@
+# Everything resolves to Any.
+from typing import Any
+
+def __getattr__(name) -> Any:
+ ...
diff --git a/src/stubs/astroid/nodes.pyi b/src/stubs/astroid/nodes.pyi
new file mode 100644
index 00000000..edbb4bff
--- /dev/null
+++ b/src/stubs/astroid/nodes.pyi
@@ -0,0 +1,5 @@
+# Everything resolves to Any.
+from typing import Any
+
+def __getattr__(name) -> Any:
+ ...
diff --git a/src/stubs/openstep_parser.pyi b/src/stubs/openstep_parser.pyi
new file mode 100644
index 00000000..edbb4bff
--- /dev/null
+++ b/src/stubs/openstep_parser.pyi
@@ -0,0 +1,5 @@
+# Everything resolves to Any.
+from typing import Any
+
+def __getattr__(name) -> Any:
+ ...
diff --git a/src/stubs/pbxproj/__init__.pyi b/src/stubs/pbxproj/__init__.pyi
new file mode 100644
index 00000000..edbb4bff
--- /dev/null
+++ b/src/stubs/pbxproj/__init__.pyi
@@ -0,0 +1,5 @@
+# Everything resolves to Any.
+from typing import Any
+
+def __getattr__(name) -> Any:
+ ...
diff --git a/src/stubs/pbxproj/pbxextensions.pyi b/src/stubs/pbxproj/pbxextensions.pyi
new file mode 100644
index 00000000..edbb4bff
--- /dev/null
+++ b/src/stubs/pbxproj/pbxextensions.pyi
@@ -0,0 +1,5 @@
+# Everything resolves to Any.
+from typing import Any
+
+def __getattr__(name) -> Any:
+ ...
diff --git a/src/stubs/pylint.pyi b/src/stubs/pylint.pyi
new file mode 100644
index 00000000..edbb4bff
--- /dev/null
+++ b/src/stubs/pylint.pyi
@@ -0,0 +1,5 @@
+# Everything resolves to Any.
+from typing import Any
+
+def __getattr__(name) -> Any:
+ ...
diff --git a/tools/batools/docs.py b/tools/batools/docs.py
index 012087ab..0c9c05e1 100755
--- a/tools/batools/docs.py
+++ b/tools/batools/docs.py
@@ -2,6 +2,8 @@
#
"""Documentation generation functionality."""
+# pyright: reportPrivateImportUsage=false
+
from __future__ import annotations
import os
diff --git a/tools/batools/dummymodule.py b/tools/batools/dummymodule.py
index c2ae4d54..02bd6746 100755
--- a/tools/batools/dummymodule.py
+++ b/tools/batools/dummymodule.py
@@ -972,7 +972,7 @@ def generate_dummy_modules(projroot: str) -> None:
)
print(
f'{Clr.BLD}{Clr.BLU}Generated {gencount} dummy-modules'
- f' {Clr.RST}(in {builddir}){Clr.RST}{Clr.BLD}{Clr.BLU}.',
+ f' {Clr.RST}(in {builddir}){Clr.RST}{Clr.BLD}{Clr.BLU}.{Clr.RST}',
flush=True,
)
diff --git a/tools/efro/dataclassio/_outputter.py b/tools/efro/dataclassio/_outputter.py
index 406265cc..b084cfeb 100644
--- a/tools/efro/dataclassio/_outputter.py
+++ b/tools/efro/dataclassio/_outputter.py
@@ -13,7 +13,7 @@ import dataclasses
import typing
import types
import datetime
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, cast, Any
from efro.util import check_utc
from efro.dataclassio._base import (
@@ -29,7 +29,6 @@ from efro.dataclassio._base import (
from efro.dataclassio._prep import PrepSession
if TYPE_CHECKING:
- from typing import Any
from efro.dataclassio._base import IOAttrs
@@ -302,7 +301,7 @@ class _Outputter:
return self._process_dict(cls, fieldpath, anntype, value, ioattrs)
if dataclasses.is_dataclass(origin):
- if not isinstance(value, origin):
+ if not isinstance(value, cast(Any, origin)):
raise TypeError(
f'Expected a {origin} for {fieldpath};'
f' found a {type(value)}.'
diff --git a/tools/efro/log.py b/tools/efro/log.py
index f48b54ce..77902265 100644
--- a/tools/efro/log.py
+++ b/tools/efro/log.py
@@ -388,11 +388,11 @@ class LogHandler(logging.Handler):
# warning log which results in another, etc.
now = time.monotonic()
# noinspection PyUnboundLocalVariable
- duration = now - starttime
+ duration = now - starttime # pyright: ignore
# noinspection PyUnboundLocalVariable
- format_duration = formattime - starttime
+ format_duration = formattime - starttime # pyright: ignore
# noinspection PyUnboundLocalVariable
- echo_duration = echotime - formattime
+ echo_duration = echotime - formattime # pyright: ignore
if duration > 0.05 and (
self._last_slow_emit_warning_time is None
or now > self._last_slow_emit_warning_time + 10.0
diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py
index 3c323856..3555fb11 100644
--- a/tools/efrotools/efrocache.py
+++ b/tools/efrotools/efrocache.py
@@ -572,7 +572,7 @@ def warm_start_cache() -> None:
base_url = get_repository_base_url()
local_cache_dir = get_local_cache_dir()
- # We maintain a starter-cache on the staging server, which is simply
+ # We maintain a starter archive on the staging server, which is simply
# a set of commonly used recent cache entries compressed into a
# single archive. If we have no local cache yet we can download and
# expand this to give us a nice head start and greatly reduce the
@@ -580,7 +580,7 @@ def warm_start_cache() -> None:
# single compressed archive is much more efficient than downloading
# thousands)
if not os.path.exists(local_cache_dir):
- print('Downloading efrocache starter-cache...', flush=True)
+ print('Downloading efrocache starter-archive...', flush=True)
# Download and decompress the starter-cache into a temp dir
# and then move it into place as our shiny new cache dir.
diff --git a/tools/efrotools/filecommand.py b/tools/efrotools/filecommand.py
index 7a543fdd..0930413e 100644
--- a/tools/efrotools/filecommand.py
+++ b/tools/efrotools/filecommand.py
@@ -37,7 +37,7 @@ class _FileBatchesRun:
# pylint: disable=useless-suppression
# pylint: disable=no-name-in-module, import-error
# noinspection PyUnresolvedReferences
- from Cocoa import NSWorkspace
+ from Cocoa import NSWorkspace # pyright: ignore
self._shared_nsworkspace = NSWorkspace.sharedWorkspace()
# pylint: enable=useless-suppression
@@ -85,6 +85,7 @@ class _FileBatchesRun:
# them out of the dir list we'll dive into and pass
# them directly to our batch for processing.
if self._include_mac_packages:
+ assert self._shared_nsworkspace is not None
for dirname in list(dirs):
fullpath = os.path.join(root, dirname)
if self._shared_nsworkspace.isFilePackageAtPath_(
diff --git a/tools/efrotools/pcommand2.py b/tools/efrotools/pcommand2.py
index 77c0fbf6..0683eb45 100644
--- a/tools/efrotools/pcommand2.py
+++ b/tools/efrotools/pcommand2.py
@@ -67,3 +67,20 @@ def openal_gather() -> None:
raise CleanError('No args expected.')
gather()
+
+
+def pyright() -> None:
+ """Run Pyright checks on project Python code."""
+ import subprocess
+
+ from efro.terminal import Clr
+
+ from efro.error import CleanError
+
+ print(f'{Clr.BLU}Running Pyright (experimental)...{Clr.RST}')
+ try:
+ subprocess.run(
+ ['pyright', '--project', '.pyrightconfig.json'], check=True
+ )
+ except Exception as exc:
+ raise CleanError('Pyright failed.') from exc
diff --git a/tools/pcommand b/tools/pcommand
index 71d93675..afc42b70 100755
--- a/tools/pcommand
+++ b/tools/pcommand
@@ -56,6 +56,7 @@ from efrotools.pcommand2 import (
sortlines,
openal_build_android,
openal_gather,
+ pyright,
)
from batools.pcommand import (
resize_image,