Work on making type-checks more strict

This commit is contained in:
Eric Froemling 2020-04-10 01:43:04 -07:00
parent 5d9e854eb8
commit 8f9a21fe32
19 changed files with 53 additions and 55 deletions

View File

@ -635,7 +635,7 @@ class App:
If there's a foreground host-activity that says it's pausable, tell it 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. 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 if (activity is not None and activity.allow_pausing
and not _ba.have_connected_clients()): and not _ba.have_connected_clients()):
from ba import _gameutils, _lang from ba import _gameutils, _lang
@ -698,7 +698,7 @@ class App:
# If we're in a host-session, tell them to end. # If we're in a host-session, tell them to end.
# This lets them tear themselves down gracefully. # 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: if host_session is not None:
# Kick off a little transaction so we'll hopefully have all the # Kick off a little transaction so we'll hopefully have all the

View File

@ -173,8 +173,7 @@ def garbage_collect(session_end: bool = True) -> None:
gc.collect() gc.collect()
# Can be handy to print this to check for leaks between games. # Can be handy to print this to check for leaks between games.
# noinspection PyUnreachableCode if bool(False):
if False: # pylint: disable=using-constant-test
print('PY OBJ COUNT', len(gc.get_objects())) print('PY OBJ COUNT', len(gc.get_objects()))
if gc.garbage: if gc.garbage:
print('PYTHON GC FOUND', len(gc.garbage), 'UNCOLLECTIBLE OBJECTS:') print('PYTHON GC FOUND', len(gc.garbage), 'UNCOLLECTIBLE OBJECTS:')

View File

@ -409,8 +409,7 @@ class TestClass(DependencyComponent):
def test_depset() -> None: def test_depset() -> None:
"""Test call to try this stuff out...""" """Test call to try this stuff out..."""
# noinspection PyUnreachableCode if bool(False):
if False: # pylint: disable=using-constant-test
print('running test_depset()...') print('running test_depset()...')
def doit() -> None: def doit() -> None:

View File

@ -52,7 +52,8 @@ class TeamGameResults:
def __init__(self) -> None: def __init__(self) -> None:
"""Instantiate a results instance.""" """Instantiate a results instance."""
self._game_set = False 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._teams: Optional[List[ReferenceType[ba.Team]]] = None
self._player_info: Optional[List[Dict[str, Any]]] = None self._player_info: Optional[List[Dict[str, Any]]] = None
self._lower_is_better: Optional[bool] = 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 if score[0]() is not None and score[1] is not None
] ]
for score in scores: for score in scores:
assert score[1] is not None
sval = winners.setdefault(score[1], []) sval = winners.setdefault(score[1], [])
team = score[0]() team = score[0]()
assert team is not None assert team is not None
@ -194,8 +196,9 @@ class TeamGameResults:
# Also group the 'None' scores. # Also group the 'None' scores.
none_teams: List[ba.Team] = [] none_teams: List[ba.Team] = []
for score in self._scores.values(): for score in self._scores.values():
if score[0]() is not None and score[1] is None: scoreteam = score[0]()
none_teams.append(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 # Add the Nones to the list (either as winners or losers
# depending on the rules). # depending on the rules).

View File

@ -27,7 +27,7 @@ import _ba
from ba._enums import TimeType, TimeFormat, SpecialChar from ba._enums import TimeType, TimeFormat, SpecialChar
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Dict, Sequence from typing import Any, Dict, Sequence, Optional
import ba import ba
TROPHY_CHARS = { TROPHY_CHARS = {
@ -141,7 +141,7 @@ def sharedobj(name: str) -> Any:
"unrecognized shared object (activity context): '" + name + "unrecognized shared object (activity context): '" + name +
"'") "'")
else: else:
session = _ba.getsession(doraise=False) session: Optional[ba.Session] = _ba.getsession(doraise=False)
if session is not None: if session is not None:
# Grab shared-objs dict (creating if necessary). # Grab shared-objs dict (creating if necessary).

View File

@ -39,9 +39,8 @@ def getclass(name: str, subclassof: Type[T]) -> Type[T]:
Category: General Utility Functions Category: General Utility Functions
If 'subclassof' is given, the class will be checked to make sure The class will be checked to make sure it is a subclass of the provided
it is a subclass of the provided class, and a TypeError will be 'subclassof' class, and a TypeError will be raised if not.
raised if not.
""" """
import importlib import importlib
splits = name.split('.') splits = name.split('.')
@ -50,7 +49,7 @@ def getclass(name: str, subclassof: Type[T]) -> Type[T]:
module = importlib.import_module(modulename) module = importlib.import_module(modulename)
cls: Type = getattr(module, classname) 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)) raise TypeError(name + ' is not a subclass of ' + str(subclassof))
return cls return cls

View File

@ -432,6 +432,7 @@ def get_valid_languages() -> List[str]:
def is_custom_unicode_char(char: str) -> bool: def is_custom_unicode_char(char: str) -> bool:
"""Return whether a char is in the custom unicode range we use.""" """Return whether a char is in the custom unicode range we use."""
if not isinstance(char, str) or len(char) != 1: assert isinstance(char, str)
raise Exception("Invalid Input; not unicode or not length 1") if len(char) != 1:
raise Exception("Invalid Input; must be length 1")
return 0xE000 <= ord(char) <= 0xF8FF return 0xE000 <= ord(char) <= 0xF8FF

View File

@ -117,7 +117,8 @@ class Level:
def set_complete(self, val: bool) -> None: def set_complete(self, val: bool) -> None:
"""Set whether or not this level is complete.""" """Set whether or not this level is complete."""
old_val = self.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: if val != old_val:
config = self._get_config_dict() config = self._get_config_dict()
config['Complete'] = val config['Complete'] = val

View File

@ -55,7 +55,8 @@ class JoinInfo:
# If we have a keyboard, grab keys for punch and pickup. # If we have a keyboard, grab keys for punch and pickup.
# FIXME: This of course is only correct on the local device; # FIXME: This of course is only correct on the local device;
# Should change this for net games. # 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: if keyboard is not None:
punch_key = keyboard.get_button_name( punch_key = keyboard.get_button_name(
_input.get_device_value(keyboard, 'buttonPunch')) _input.get_device_value(keyboard, 'buttonPunch'))
@ -398,8 +399,7 @@ class Chooser:
# list might have changed. # list might have changed.
input_device = self._player.get_input_device() input_device = self._player.get_input_device()
is_remote = input_device.is_remote_client is_remote = input_device.is_remote_client
is_test_input = (input_device is not None is_test_input = input_device.name.startswith('TestInput')
and input_device.name.startswith('TestInput'))
# Pull this player's list of unlocked characters. # Pull this player's list of unlocked characters.
if is_remote: if is_remote:

View File

@ -19,11 +19,16 @@
# SOFTWARE. # SOFTWARE.
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
"""Functionality related to modding.""" """Functionality related to modding."""
from __future__ import annotations
from typing import TYPE_CHECKING
import os import os
import _ba import _ba
if TYPE_CHECKING:
from typing import Optional
def get_human_readable_user_scripts_path() -> str: def get_human_readable_user_scripts_path() -> str:
"""Return a human readable location of user-scripts. """Return a human readable location of user-scripts.
@ -32,7 +37,7 @@ def get_human_readable_user_scripts_path() -> str:
""" """
from ba import _lang from ba import _lang
app = _ba.app app = _ba.app
path = app.user_scripts_directory path: Optional[str] = app.user_scripts_directory
if path is None: if path is None:
return '<Not Available>' return '<Not Available>'
@ -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 # only visible to the user's processes and thus not really useful printed
# in its entirety; lets print it as <External Storage>/myfilepath. # in its entirety; lets print it as <External Storage>/myfilepath.
if app.platform == 'android': 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 if (ext_storage_path is not None
and app.user_scripts_directory.startswith(ext_storage_path)): and app.user_scripts_directory.startswith(ext_storage_path)):
path = ('<' + path = ('<' +
@ -75,7 +81,7 @@ def show_user_scripts() -> None:
# they can see it. # they can see it.
if app.platform == 'android': if app.platform == 'android':
try: try:
usd = app.user_scripts_directory usd: Optional[str] = app.user_scripts_directory
if usd is not None and os.path.isdir(usd): if usd is not None and os.path.isdir(usd):
file_name = usd + '/about_this_folder.txt' file_name = usd + '/about_this_folder.txt'
with open(file_name, 'w') as outfile: with open(file_name, 'w') as outfile:

View File

@ -83,7 +83,7 @@ class MusicPlayer:
def __init__(self) -> None: def __init__(self) -> None:
self._have_set_initial_volume = False self._have_set_initial_volume = False
self._entry_to_play = None self._entry_to_play: Optional[Any] = None
self._volume = 1.0 self._volume = 1.0
self._actually_playing = False self._actually_playing = False

View File

@ -32,6 +32,7 @@ import _ba
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Any, Dict, Union, Callable, Optional from typing import Any, Dict, Union, Callable, Optional
import socket import socket
import ba
ServerCallbackType = Callable[[Union[None, Dict[str, Any]]], None] ServerCallbackType = Callable[[Union[None, Dict[str, Any]]], None]
@ -82,7 +83,7 @@ class ServerCallThread(threading.Thread):
self._context = _ba.Context('current') self._context = _ba.Context('current')
# Save and restore the context we were created from. # 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( self._activity = weakref.ref(
activity) if activity is not None else None activity) if activity is not None else None

View File

@ -746,7 +746,7 @@ class Session:
# Pass it to the current activity if it has already begun # Pass it to the current activity if it has already begun
# (otherwise it'll get passed once begin is called). # (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) and not activity.is_joining_activity)
# If we're not allowing mid-game joins, don't pass; just announce # If we're not allowing mid-game joins, don't pass; just announce

View File

@ -256,7 +256,7 @@ class Stats:
self.orchestrahitsound3: Optional[ba.Sound] = None self.orchestrahitsound3: Optional[ba.Sound] = None
self.orchestrahitsound4: 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.""" """Set the current activity for this instance."""
self._activity = None if activity is None else weakref.ref(activity) self._activity = None if activity is None else weakref.ref(activity)

View File

@ -30,7 +30,7 @@ if TYPE_CHECKING:
from typing import Dict, List, Any 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.""" """Given a tournament entry, return strings for its prize levels."""
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
from ba._enums import SpecialChar from ba._enums import SpecialChar
@ -54,22 +54,9 @@ def get_tournament_prize_strings(entry: Dict[str, Any]) -> List:
pvval = '' pvval = ''
if trophy_type is not None: if trophy_type is not None:
pvval += get_trophy_string(trophy_type) pvval += get_trophy_string(trophy_type)
# trophy_chars = {
# '1': SpecialChar.TROPHY1, # If we've got trophies but not for this entry, throw some space
# '2': SpecialChar.TROPHY2, # in to compensate so the ticket counts line up.
# '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 prize is not None: if prize is not None:
pvval = _ba.charstr( pvval = _ba.charstr(
SpecialChar.TICKET_BACKING) + str(prize) + pvval SpecialChar.TICKET_BACKING) + str(prize) + pvval

View File

@ -1028,8 +1028,9 @@ class CoopScoreScreen(ba.Activity):
self._score_link) self._score_link)
self._score_loading_status = None self._score_loading_status = None
if 'tournamentSecondsRemaining' in results: if 'tournamentSecondsRemaining' in results:
self._tournament_time_remaining = ( secs_remaining = results['tournamentSecondsRemaining']
results['tournamentSecondsRemaining']) assert isinstance(secs_remaining, int)
self._tournament_time_remaining = secs_remaining
self._tournament_time_remaining_text_timer = ba.Timer( self._tournament_time_remaining_text_timer = ba.Timer(
1.0, 1.0,
ba.WeakCall( ba.WeakCall(
@ -1088,7 +1089,7 @@ class CoopScoreScreen(ba.Activity):
elif p_count == 4: elif p_count == 4:
scale = 0.5 scale = 0.5
# make sure there's at least 10.. # Make sure there's at least 10.
while len(self._show_info['tops']) < 10: while len(self._show_info['tops']) < 10:
self._show_info['tops'].append([0, '-']) self._show_info['tops'].append([0, '-'])

View File

@ -34,7 +34,7 @@ import traceback
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
if 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]: def _get_default_config() -> Dict[str, Any]:
@ -176,7 +176,8 @@ def _run_process_until_exit(process: subprocess.Popen,
process.stdin.flush() process.stdin.flush()
config_dirty = False config_dirty = False
code = process.poll() code: Optional[int] = process.poll()
if code is not None: if code is not None:
print('BallisticaCore exited with code ' + str(code)) print('BallisticaCore exited with code ' + str(code))
break break

View File

@ -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 # Let's print a list of modules with no detected deps so we can make sure
# this is behaving. # this is behaving.
if no_deps_modules: if no_deps_modules:
# noinspection PyUnreachableCode if bool(False):
if False: # pylint: disable=using-constant-test
print('NOTE: no dependencies found for:', print('NOTE: no dependencies found for:',
', '.join(no_deps_modules)) ', '.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) mname2 = paths_to_names.get(fname)
if mname2 is None: if mname2 is None:
raise Exception('unable to get module name for "' + fname + '"') 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 # 'statement' count seems to be new and always non-zero; ignore it
if counts is not None: if counts is not None:
@ -645,9 +644,9 @@ def _run_idea_inspections(projroot: Path,
if result.returncode != 0: if result.returncode != 0:
# In verbose mode this stuff got printed already. # In verbose mode this stuff got printed already.
if not verbose: if not verbose:
stdout = (result.stdout.decode() if isinstance( stdout = (result.stdout.decode() if isinstance( # type: ignore
result.stdout, bytes) else str(result.stdout)) 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)) result.stdout, bytes) else str(result.stdout))
print(f'{displayname} inspection failure stdout:\n{stdout}' + print(f'{displayname} inspection failure stdout:\n{stdout}' +
f'{displayname} inspection failure stderr:\n{stderr}') f'{displayname} inspection failure stderr:\n{stderr}')

View File

@ -317,6 +317,7 @@ def tool_config_install() -> None:
warn_unused_ignores = True warn_unused_ignores = True
warn_return_any = True warn_return_any = True
warn_redundant_casts = True warn_redundant_casts = True
warn_unreachable=True
disallow_incomplete_defs = True disallow_incomplete_defs = True
disallow_untyped_defs = True disallow_untyped_defs = True
disallow_untyped_decorators = True disallow_untyped_decorators = True