diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 29c6fedb..32fa9df8 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -635,7 +635,7 @@ class App: If there's a foreground host-activity that says it's pausable, tell it to pause ..we now no longer pause if there are connected clients. """ - activity = _ba.get_foreground_host_activity() + activity: Optional[ba.Activity] = _ba.get_foreground_host_activity() if (activity is not None and activity.allow_pausing and not _ba.have_connected_clients()): from ba import _gameutils, _lang @@ -698,7 +698,7 @@ class App: # If we're in a host-session, tell them to end. # This lets them tear themselves down gracefully. - host_session = _ba.get_foreground_host_session() + host_session: Optional[ba.Session] = _ba.get_foreground_host_session() if host_session is not None: # Kick off a little transaction so we'll hopefully have all the diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py index 2b974b87..91307be2 100644 --- a/assets/src/ba_data/python/ba/_apputils.py +++ b/assets/src/ba_data/python/ba/_apputils.py @@ -173,8 +173,7 @@ def garbage_collect(session_end: bool = True) -> None: gc.collect() # Can be handy to print this to check for leaks between games. - # noinspection PyUnreachableCode - if False: # pylint: disable=using-constant-test + if bool(False): print('PY OBJ COUNT', len(gc.get_objects())) if gc.garbage: print('PYTHON GC FOUND', len(gc.garbage), 'UNCOLLECTIBLE OBJECTS:') diff --git a/assets/src/ba_data/python/ba/_dependency.py b/assets/src/ba_data/python/ba/_dependency.py index b7ba86cc..082f05ef 100644 --- a/assets/src/ba_data/python/ba/_dependency.py +++ b/assets/src/ba_data/python/ba/_dependency.py @@ -409,8 +409,7 @@ class TestClass(DependencyComponent): def test_depset() -> None: """Test call to try this stuff out...""" - # noinspection PyUnreachableCode - if False: # pylint: disable=using-constant-test + if bool(False): print('running test_depset()...') def doit() -> None: diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index 47146043..0be8a00a 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -52,7 +52,8 @@ class TeamGameResults: def __init__(self) -> None: """Instantiate a results instance.""" self._game_set = False - self._scores: Dict[int, Tuple[ReferenceType[ba.Team], int]] = {} + self._scores: Dict[int, Tuple[ReferenceType[ba.Team], + Optional[int]]] = {} self._teams: Optional[List[ReferenceType[ba.Team]]] = None self._player_info: Optional[List[Dict[str, Any]]] = None self._lower_is_better: Optional[bool] = None @@ -183,6 +184,7 @@ class TeamGameResults: if score[0]() is not None and score[1] is not None ] for score in scores: + assert score[1] is not None sval = winners.setdefault(score[1], []) team = score[0]() assert team is not None @@ -194,8 +196,9 @@ class TeamGameResults: # Also group the 'None' scores. none_teams: List[ba.Team] = [] for score in self._scores.values(): - if score[0]() is not None and score[1] is None: - none_teams.append(score[0]()) + scoreteam = score[0]() + if scoreteam is not None and score[1] is None: + none_teams.append(scoreteam) # Add the Nones to the list (either as winners or losers # depending on the rules). diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index 059eef51..4d92f64e 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -27,7 +27,7 @@ import _ba from ba._enums import TimeType, TimeFormat, SpecialChar if TYPE_CHECKING: - from typing import Any, Dict, Sequence + from typing import Any, Dict, Sequence, Optional import ba TROPHY_CHARS = { @@ -141,7 +141,7 @@ def sharedobj(name: str) -> Any: "unrecognized shared object (activity context): '" + name + "'") else: - session = _ba.getsession(doraise=False) + session: Optional[ba.Session] = _ba.getsession(doraise=False) if session is not None: # Grab shared-objs dict (creating if necessary). diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 92519239..e948c4f6 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -39,9 +39,8 @@ def getclass(name: str, subclassof: Type[T]) -> Type[T]: Category: General Utility Functions - If 'subclassof' is given, the class will be checked to make sure - it is a subclass of the provided class, and a TypeError will be - raised if not. + The class will be checked to make sure it is a subclass of the provided + 'subclassof' class, and a TypeError will be raised if not. """ import importlib splits = name.split('.') @@ -50,7 +49,7 @@ def getclass(name: str, subclassof: Type[T]) -> Type[T]: module = importlib.import_module(modulename) cls: Type = getattr(module, classname) - if subclassof is not None and not issubclass(cls, subclassof): + if not issubclass(cls, subclassof): raise TypeError(name + ' is not a subclass of ' + str(subclassof)) return cls diff --git a/assets/src/ba_data/python/ba/_lang.py b/assets/src/ba_data/python/ba/_lang.py index 8707f76a..b9c54f17 100644 --- a/assets/src/ba_data/python/ba/_lang.py +++ b/assets/src/ba_data/python/ba/_lang.py @@ -432,6 +432,7 @@ def get_valid_languages() -> List[str]: def is_custom_unicode_char(char: str) -> bool: """Return whether a char is in the custom unicode range we use.""" - if not isinstance(char, str) or len(char) != 1: - raise Exception("Invalid Input; not unicode or not length 1") + assert isinstance(char, str) + if len(char) != 1: + raise Exception("Invalid Input; must be length 1") return 0xE000 <= ord(char) <= 0xF8FF diff --git a/assets/src/ba_data/python/ba/_level.py b/assets/src/ba_data/python/ba/_level.py index d5271d9b..687bae40 100644 --- a/assets/src/ba_data/python/ba/_level.py +++ b/assets/src/ba_data/python/ba/_level.py @@ -117,7 +117,8 @@ class Level: def set_complete(self, val: bool) -> None: """Set whether or not this level is complete.""" old_val = self.complete - assert isinstance(old_val, bool) and isinstance(val, bool) + assert isinstance(old_val, bool) + assert isinstance(val, bool) if val != old_val: config = self._get_config_dict() config['Complete'] = val diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index 85ff0f1d..f3941a74 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -55,7 +55,8 @@ class JoinInfo: # If we have a keyboard, grab keys for punch and pickup. # FIXME: This of course is only correct on the local device; # Should change this for net games. - keyboard = _ba.get_input_device('Keyboard', '#1', doraise=False) + keyboard: Optional[ba.InputDevice] = _ba.get_input_device( + 'Keyboard', '#1', doraise=False) if keyboard is not None: punch_key = keyboard.get_button_name( _input.get_device_value(keyboard, 'buttonPunch')) @@ -398,8 +399,7 @@ class Chooser: # list might have changed. input_device = self._player.get_input_device() is_remote = input_device.is_remote_client - is_test_input = (input_device is not None - and input_device.name.startswith('TestInput')) + is_test_input = input_device.name.startswith('TestInput') # Pull this player's list of unlocked characters. if is_remote: diff --git a/assets/src/ba_data/python/ba/_modutils.py b/assets/src/ba_data/python/ba/_modutils.py index b4d8cd2a..e24fe638 100644 --- a/assets/src/ba_data/python/ba/_modutils.py +++ b/assets/src/ba_data/python/ba/_modutils.py @@ -19,11 +19,16 @@ # SOFTWARE. # ----------------------------------------------------------------------------- """Functionality related to modding.""" +from __future__ import annotations +from typing import TYPE_CHECKING import os import _ba +if TYPE_CHECKING: + from typing import Optional + def get_human_readable_user_scripts_path() -> str: """Return a human readable location of user-scripts. @@ -32,7 +37,7 @@ def get_human_readable_user_scripts_path() -> str: """ from ba import _lang app = _ba.app - path = app.user_scripts_directory + path: Optional[str] = app.user_scripts_directory if path is None: return '' @@ -40,7 +45,8 @@ def get_human_readable_user_scripts_path() -> str: # only visible to the user's processes and thus not really useful printed # in its entirety; lets print it as /myfilepath. if app.platform == 'android': - ext_storage_path = (_ba.android_get_external_storage_path()) + ext_storage_path: Optional[str] = ( + _ba.android_get_external_storage_path()) if (ext_storage_path is not None and app.user_scripts_directory.startswith(ext_storage_path)): path = ('<' + @@ -75,7 +81,7 @@ def show_user_scripts() -> None: # they can see it. if app.platform == 'android': try: - usd = app.user_scripts_directory + usd: Optional[str] = app.user_scripts_directory if usd is not None and os.path.isdir(usd): file_name = usd + '/about_this_folder.txt' with open(file_name, 'w') as outfile: diff --git a/assets/src/ba_data/python/ba/_music.py b/assets/src/ba_data/python/ba/_music.py index ac960533..4230a40f 100644 --- a/assets/src/ba_data/python/ba/_music.py +++ b/assets/src/ba_data/python/ba/_music.py @@ -83,7 +83,7 @@ class MusicPlayer: def __init__(self) -> None: self._have_set_initial_volume = False - self._entry_to_play = None + self._entry_to_play: Optional[Any] = None self._volume = 1.0 self._actually_playing = False diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index 8369d335..f28eaab1 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -32,6 +32,7 @@ import _ba if TYPE_CHECKING: from typing import Any, Dict, Union, Callable, Optional import socket + import ba ServerCallbackType = Callable[[Union[None, Dict[str, Any]]], None] @@ -82,7 +83,7 @@ class ServerCallThread(threading.Thread): self._context = _ba.Context('current') # Save and restore the context we were created from. - activity = _ba.getactivity(doraise=False) + activity: Optional[ba.Activity] = _ba.getactivity(doraise=False) self._activity = weakref.ref( activity) if activity is not None else None diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index cdfeac9d..52671049 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -746,7 +746,7 @@ class Session: # Pass it to the current activity if it has already begun # (otherwise it'll get passed once begin is called). - pass_to_activity = (activity is not None and activity.has_begun() + pass_to_activity = (activity.has_begun() and not activity.is_joining_activity) # If we're not allowing mid-game joins, don't pass; just announce diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index 6954aea2..6a24cea2 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -256,7 +256,7 @@ class Stats: self.orchestrahitsound3: Optional[ba.Sound] = None self.orchestrahitsound4: Optional[ba.Sound] = None - def set_activity(self, activity: ba.Activity) -> None: + def set_activity(self, activity: Optional[ba.Activity]) -> None: """Set the current activity for this instance.""" self._activity = None if activity is None else weakref.ref(activity) diff --git a/assets/src/ba_data/python/ba/_tournament.py b/assets/src/ba_data/python/ba/_tournament.py index f5491a3a..38b0768c 100644 --- a/assets/src/ba_data/python/ba/_tournament.py +++ b/assets/src/ba_data/python/ba/_tournament.py @@ -30,7 +30,7 @@ if TYPE_CHECKING: from typing import Dict, List, Any -def get_tournament_prize_strings(entry: Dict[str, Any]) -> List: +def get_tournament_prize_strings(entry: Dict[str, Any]) -> List[str]: """Given a tournament entry, return strings for its prize levels.""" # pylint: disable=too-many-locals from ba._enums import SpecialChar @@ -54,22 +54,9 @@ def get_tournament_prize_strings(entry: Dict[str, Any]) -> List: pvval = '' if trophy_type is not None: pvval += get_trophy_string(trophy_type) - # trophy_chars = { - # '1': SpecialChar.TROPHY1, - # '2': SpecialChar.TROPHY2, - # '3': SpecialChar.TROPHY3, - # '0a': SpecialChar.TROPHY0A, - # '0b': SpecialChar.TROPHY0B, - # '4': SpecialChar.TROPHY4 - # } - # if trophy_type in trophy_chars: - # pvval += _bs.specialchar(trophy_chars[trophy_type]) - # else: - # from ba import err - # err.print_error( - # f"unrecognized trophy type: {trophy_type}", once=True) - # if we've got trophies but not for this entry, throw some space - # in to compensate so the ticket counts line up + + # If we've got trophies but not for this entry, throw some space + # in to compensate so the ticket counts line up. if prize is not None: pvval = _ba.charstr( SpecialChar.TICKET_BACKING) + str(prize) + pvval diff --git a/assets/src/ba_data/python/bastd/activity/coopscorescreen.py b/assets/src/ba_data/python/bastd/activity/coopscorescreen.py index f96ca753..35967cd5 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscorescreen.py +++ b/assets/src/ba_data/python/bastd/activity/coopscorescreen.py @@ -1028,8 +1028,9 @@ class CoopScoreScreen(ba.Activity): self._score_link) self._score_loading_status = None if 'tournamentSecondsRemaining' in results: - self._tournament_time_remaining = ( - results['tournamentSecondsRemaining']) + secs_remaining = results['tournamentSecondsRemaining'] + assert isinstance(secs_remaining, int) + self._tournament_time_remaining = secs_remaining self._tournament_time_remaining_text_timer = ba.Timer( 1.0, ba.WeakCall( @@ -1088,7 +1089,7 @@ class CoopScoreScreen(ba.Activity): elif p_count == 4: scale = 0.5 - # make sure there's at least 10.. + # Make sure there's at least 10. while len(self._show_info['tops']) < 10: self._show_info['tops'].append([0, '-']) diff --git a/assets/src/server/server.py b/assets/src/server/server.py index 3141f049..336b8b73 100755 --- a/assets/src/server/server.py +++ b/assets/src/server/server.py @@ -34,7 +34,7 @@ import traceback from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Dict, Any, Sequence + from typing import Dict, Any, Sequence, Optional def _get_default_config() -> Dict[str, Any]: @@ -176,7 +176,8 @@ def _run_process_until_exit(process: subprocess.Popen, process.stdin.flush() config_dirty = False - code = process.poll() + code: Optional[int] = process.poll() + if code is not None: print('BallisticaCore exited with code ' + str(code)) break diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index edaea818..1983d6fb 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -467,8 +467,7 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str], # Let's print a list of modules with no detected deps so we can make sure # this is behaving. if no_deps_modules: - # noinspection PyUnreachableCode - if False: # pylint: disable=using-constant-test + if bool(False): print('NOTE: no dependencies found for:', ', '.join(no_deps_modules)) @@ -487,7 +486,7 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str], mname2 = paths_to_names.get(fname) if mname2 is None: raise Exception('unable to get module name for "' + fname + '"') - counts = (None if mname2 is None else stats_by_module.get(mname2)) + counts = stats_by_module.get(mname2) # 'statement' count seems to be new and always non-zero; ignore it if counts is not None: @@ -645,9 +644,9 @@ def _run_idea_inspections(projroot: Path, if result.returncode != 0: # In verbose mode this stuff got printed already. if not verbose: - stdout = (result.stdout.decode() if isinstance( + stdout = (result.stdout.decode() if isinstance( # type: ignore result.stdout, bytes) else str(result.stdout)) - stderr = (result.stderr.decode() if isinstance( + stderr = (result.stderr.decode() if isinstance( # type: ignore result.stdout, bytes) else str(result.stdout)) print(f'{displayname} inspection failure stdout:\n{stdout}' + f'{displayname} inspection failure stderr:\n{stderr}') diff --git a/tools/efrotools/snippets.py b/tools/efrotools/snippets.py index d4f982c3..fd2d3270 100644 --- a/tools/efrotools/snippets.py +++ b/tools/efrotools/snippets.py @@ -317,6 +317,7 @@ def tool_config_install() -> None: warn_unused_ignores = True warn_return_any = True warn_redundant_casts = True + warn_unreachable=True disallow_incomplete_defs = True disallow_untyped_defs = True disallow_untyped_decorators = True