diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 653af8f8..081c6f81 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1076,6 +1076,7 @@ minusbutton minval minver + minversion mios mipmap mipmaps @@ -1275,6 +1276,7 @@ pickletools pickupmats pipestatus + pipname pkey pkgutil playerlostspaz diff --git a/assets/src/ba_data/python/ba/_assetmanager.py b/assets/src/ba_data/python/ba/_assetmanager.py index 7d5ee4e3..dcf58d67 100644 --- a/assets/src/ba_data/python/ba/_assetmanager.py +++ b/assets/src/ba_data/python/ba/_assetmanager.py @@ -176,14 +176,13 @@ def fetch_url(url: str, filename: Path, asset_gather: AssetGather) -> None: """Fetch a given url to a given filename for a given AssetGather. """ - # pylint: disable=too-many-locals import socket # We don't want to keep the provided AssetGather alive, but we want # to abort if it dies. assert isinstance(asset_gather, AssetGather) - weak_gather = weakref.ref(asset_gather) + # weak_gather = weakref.ref(asset_gather) # Pass a very short timeout to urllib so we have opportunities # to cancel even with network blockage. diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py index b5a7d1a7..cc14d8bb 100644 --- a/assets/src/ba_data/python/ba/_hooks.py +++ b/assets/src/ba_data/python/ba/_hooks.py @@ -182,9 +182,6 @@ def purchases_restored_message() -> None: def dismiss_wii_remotes_window() -> None: call = _ba.app.dismiss_wii_remotes_window_call if call is not None: - # Weird; this seems to trigger pylint only sometimes. - # pylint: disable=useless-suppression - # pylint: disable=not-callable call() diff --git a/assets/src/ba_data/python/ba/_lang.py b/assets/src/ba_data/python/ba/_lang.py index 49a1165c..a72ce297 100644 --- a/assets/src/ba_data/python/ba/_lang.py +++ b/assets/src/ba_data/python/ba/_lang.py @@ -63,7 +63,7 @@ class Lstr: subs=[('${NAME}', ba.Lstr(resource='res_b'))]) """ - # pylint: disable=redefined-outer-name + # pylint: disable=redefined-outer-name, dangerous-default-value # noinspection PyDefaultArgument @overload def __init__(self, @@ -93,7 +93,7 @@ class Lstr: """Create an Lstr from a raw string value.""" ... - # pylint: enable=redefined-outer-name + # pylint: enable=redefined-outer-name, dangerous-default-value def __init__(self, *args: Any, **keywds: Any) -> None: """Instantiate a Lstr. diff --git a/assets/src/ba_data/python/bacommon/err.py b/assets/src/ba_data/python/bacommon/err.py index b33036c4..aa77f4d4 100644 --- a/assets/src/ba_data/python/bacommon/err.py +++ b/assets/src/ba_data/python/bacommon/err.py @@ -32,5 +32,5 @@ class RemoteError(Exception): """An error occurred on the other end of some connection.""" def __str__(self) -> str: - s = ''.join(str(arg) for arg in self.args) # pylint: disable=E1133 + s = ''.join(str(arg) for arg in self.args) return f'Remote Exception Follows:\n{s}' diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index e41ad7e0..b2baeba4 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -462,7 +462,7 @@ class Spaz(ba.Actor): if t_ms - self.last_punch_time_ms >= self._punch_cooldown: if self.punch_callback is not None: self.punch_callback(self) - self._punched_nodes = set() # reset this.. + self._punched_nodes = set() # Reset this. self.last_punch_time_ms = t_ms self.node.punch_pressed = True if not self.node.hold_node: diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 1c53c554..1688c7b8 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -463,7 +463,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): def spawn_player_spaz(self, *args: Any, **keywds: Any) -> Any: """Intercept new spazzes and add our team material for them.""" # (chill pylint; we're passing our exact args to parent call) - # pylint: disable=arguments-differ + # pylint: disable=signature-differs spaz = ba.TeamGameActivity.spawn_player_spaz(self, *args, **keywds) player = spaz.player player.gamedata['touching_own_flag'] = 0 diff --git a/assets/src/ba_data/python/efro/entity/_value.py b/assets/src/ba_data/python/efro/entity/_value.py index 592ec95d..386464e9 100644 --- a/assets/src/ba_data/python/efro/entity/_value.py +++ b/assets/src/ba_data/python/efro/entity/_value.py @@ -89,7 +89,7 @@ class SimpleValue(TypedValue[T]): def __repr__(self) -> str: if self._target_type is not None: return f'' - return f'' + return '' def get_default_data(self) -> Any: return self._default_data @@ -286,7 +286,7 @@ class Float3Value(SimpleValue[Tuple[float, float, float]]): super().__init__(default, store_default) def __repr__(self) -> str: - return f'' + return '' def filter_input(self, data: Any, error: bool) -> Any: if (not isinstance(data, abc.Sequence) or len(data) != 3 diff --git a/assets/src/ba_data/python/efro/jsonutils.py b/assets/src/ba_data/python/efro/jsonutils.py index 7a2aad6f..383380bb 100644 --- a/assets/src/ba_data/python/efro/jsonutils.py +++ b/assets/src/ba_data/python/efro/jsonutils.py @@ -40,7 +40,7 @@ _pytz_utc: Any # (in which case it should be installed as a dependency anyway) try: import pytz - _pytz_utc = pytz.utc # pylint: disable=invalid-name + _pytz_utc = pytz.utc except ModuleNotFoundError: _pytz_utc = None # pylint: disable=invalid-name @@ -48,7 +48,7 @@ except ModuleNotFoundError: class ExtendedJSONEncoder(json.JSONEncoder): """Custom json encoder supporting additional types.""" - def default(self, obj: Any) -> Any: # pylint: disable=E0202, W0221 + def default(self, obj: Any) -> Any: # pylint: disable=W0221 if isinstance(obj, datetime.datetime): # We only support timezone-aware utc times. diff --git a/config/toolconfigsrc/pylintrc b/config/toolconfigsrc/pylintrc index 3300f2f1..b1293b74 100644 --- a/config/toolconfigsrc/pylintrc +++ b/config/toolconfigsrc/pylintrc @@ -47,12 +47,16 @@ disable=bad-continuation # with having a bunch of optional args in some cases. # similarities # Not gonna touch this for now; maybe later. Bigger fish to fry. +# not-callable +# Seeming to get a number of false positives for this, and mypy covers +# this case well. disable=broad-except, too-few-public-methods, no-self-use, too-many-instance-attributes, too-many-arguments, - similarities + similarities, + not-callable # We want to know whenever we can get rid of suppression statements. enable=useless-suppression diff --git a/docs/ba_module.md b/docs/ba_module.md index f4b7993e..d045941f 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

last updated on 2020-04-26 for Ballistica version 1.5.0 build 20001

+

last updated on 2020-04-27 for Ballistica version 1.5.0 build 20001

This page documents the Python classes and functions in the 'ba' module, which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please let me know. Happy modding!


diff --git a/tools/batools/build.py b/tools/batools/build.py index 597a21d9..ac3a5d5a 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -24,28 +24,38 @@ from __future__ import annotations import os import sys from enum import Enum +import datetime +from dataclasses import dataclass import subprocess from pathlib import Path from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import List, Sequence + from typing import List, Sequence, Optional CLRBLU = '\033[94m' # Blue. CLRHDR = '\033[95m' # Header. CLREND = '\033[0m' # End. -# Python modules we require for this project. -# (module name, required version, pip package (if it differs from module name)) -REQUIRED_PYTHON_MODULES = [ - ('pylint', [2, 4, 4], None), - ('mypy', [0, 770], None), - ('yapf', [0, 30, 0], None), - ('typing_extensions', None, None), - ('pytz', None, None), - ('yaml', None, 'PyYAML'), - ('requests', None, None), - ('pytest', None, None), + +# Python pip packages we require for this project. +@dataclass +class PipRequirement: + """A pip package required by our project.""" + modulename: str + minversion: Optional[List[int]] = None # None implies no min version. + pipname: Optional[str] = None # None implies same as modulename. + + +PIP_REQUIREMENTS = [ + PipRequirement(modulename='pylint', minversion=[2, 5, 0]), + PipRequirement(modulename='mypy', minversion=[0, 770]), + PipRequirement(modulename='yapf', minversion=[0, 30, 0]), + PipRequirement(modulename='typing_extensions'), + PipRequirement(modulename='pytz'), + PipRequirement(modulename='yaml', pipname='PyYAML'), + PipRequirement(modulename='requests'), + PipRequirement(modulename='pytest'), ] # Parts of full-tests suite we only run on particular days. @@ -231,7 +241,6 @@ def gen_fulltest_buildfile_android() -> None: (so we see nice pretty split-up build trees) """ # pylint: disable=too-many-branches - import datetime # Its a pretty big time-suck building all architectures for # all of our subplatforms, so lets usually just build a single one. @@ -290,7 +299,6 @@ def gen_fulltest_buildfile_windows() -> None: (so we see nice pretty split-up build trees) """ - import datetime dayoffset = datetime.datetime.now().timetuple().tm_yday @@ -338,7 +346,6 @@ def gen_fulltest_buildfile_apple() -> None: (so we see nice pretty split-up build trees) """ # pylint: disable=too-many-branches - import datetime dayoffset = datetime.datetime.now().timetuple().tm_yday @@ -403,7 +410,6 @@ def gen_fulltest_buildfile_linux() -> None: (so we see nice pretty split-up build trees) """ - import datetime dayoffset = datetime.datetime.now().timetuple().tm_yday @@ -468,7 +474,7 @@ def checkenv() -> None: # Make sure they've got curl. if subprocess.run(['which', 'curl'], check=False, capture_output=True).returncode != 0: - raise RuntimeError(f'curl is required; please install it.') + raise RuntimeError('curl is required; please install it.') # Make sure they've got our target python version. if subprocess.run(['which', PYTHON_BIN], check=False, @@ -484,7 +490,10 @@ def checkenv() -> None: 'pip (for {PYTHON_BIN}) is required; please install it.') # Check for some required python modules. - for modname, minver, packagename in REQUIRED_PYTHON_MODULES: + for req in PIP_REQUIREMENTS: + modname = req.modulename + minver = req.minversion + packagename = req.pipname if packagename is None: packagename = modname if minver is not None: @@ -510,7 +519,9 @@ def checkenv() -> None: if vnums < minver: raise RuntimeError( f'{packagename} ver. {_vstr(minver)} or newer required;' - f' found {_vstr(vnums)}') + f' found {_vstr(vnums)}.\n' + f'To upgrade it, try: "{PYTHON_BIN}' + f' -m pip install {packagename} --upgrade"') print('Environment ok.', flush=True) @@ -518,8 +529,8 @@ def checkenv() -> None: def get_pip_reqs() -> List[str]: """Return the pip requirements needed to build/run stuff.""" out: List[str] = [] - for module in REQUIRED_PYTHON_MODULES: - name = module[0] if module[2] is None else module[2] + for req in PIP_REQUIREMENTS: + name = req.modulename if req.pipname is None else req.pipname assert isinstance(name, str) out.append(name) return out diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py index 4cd75f4d..81c95769 100644 --- a/tools/efrotools/efrocache.py +++ b/tools/efrotools/efrocache.py @@ -400,7 +400,7 @@ def warm_start_cache() -> None: print('Decompressing starter-cache...', flush=True) run('tar -xf startercache.tar.xz') run(f'mv efrocache {CACHE_DIR_NAME}') - run(f'rm startercache.tar.xz') + run('rm startercache.tar.xz') print('Starter-cache fetched successfully!' ' (should speed up asset builds)') diff --git a/tools/efrotools/jsontools.py b/tools/efrotools/jsontools.py index fc91a2ab..e620a5b7 100644 --- a/tools/efrotools/jsontools.py +++ b/tools/efrotools/jsontools.py @@ -48,7 +48,7 @@ class NoIndentEncoder(json.JSONEncoder): del self.kwargs['indent'] self._replacement_map: Dict = {} - def default(self, o: Any) -> Any: # pylint: disable=method-hidden + def default(self, o: Any) -> Any: import uuid if isinstance(o, NoIndent): diff --git a/tools/snippets b/tools/snippets index 7dfedb3a..71302778 100755 --- a/tools/snippets +++ b/tools/snippets @@ -528,7 +528,7 @@ def install_pip_reqs() -> None: subprocess.run([PYTHON_BIN, '-m', 'pip', 'install', '--upgrade'] + get_pip_reqs(), check=True) - print(f'All pip requirements installed!') + print('All pip requirements installed!') def checkenv() -> None: