From 5b5aee6faf3f8f219dd780f3274db7e3ad3aee5a Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Thu, 21 May 2020 18:47:28 +0300 Subject: [PATCH] Exceptions typing in ba module --- assets/src/ba_data/python/ba/_account.py | 2 +- assets/src/ba_data/python/ba/_achievement.py | 4 ++-- assets/src/ba_data/python/ba/_app.py | 2 +- assets/src/ba_data/python/ba/_campaign.py | 10 ++++++---- assets/src/ba_data/python/ba/_coopsession.py | 2 +- assets/src/ba_data/python/ba/_dependency.py | 2 +- assets/src/ba_data/python/ba/_error.py | 2 +- assets/src/ba_data/python/ba/_gameactivity.py | 4 ++-- assets/src/ba_data/python/ba/_gameutils.py | 14 +++++++------- assets/src/ba_data/python/ba/_lang.py | 11 ++++++----- assets/src/ba_data/python/ba/_level.py | 2 +- assets/src/ba_data/python/ba/_lobby.py | 3 ++- assets/src/ba_data/python/ba/_map.py | 17 ++++++++++------- assets/src/ba_data/python/ba/_meta.py | 2 +- assets/src/ba_data/python/ba/_music.py | 15 ++++++++------- assets/src/ba_data/python/ba/_netutils.py | 8 ++++---- assets/src/ba_data/python/ba/_player.py | 2 +- assets/src/ba_data/python/ba/_playlist.py | 2 +- assets/src/ba_data/python/ba/_store.py | 2 +- assets/src/ba_data/python/ba/ui/__init__.py | 4 ++-- 20 files changed, 59 insertions(+), 51 deletions(-) diff --git a/assets/src/ba_data/python/ba/_account.py b/assets/src/ba_data/python/ba/_account.py index 65143a64..228fa8fb 100644 --- a/assets/src/ba_data/python/ba/_account.py +++ b/assets/src/ba_data/python/ba/_account.py @@ -83,7 +83,7 @@ def get_league_rank_points(data: Optional[Dict[str, Any]], assert isinstance(trophies_total, int) return trophies_total if subset is not None: - raise Exception('invalid subset value: ' + str(subset)) + raise ValueError('invalid subset value: ' + str(subset)) if data['p']: pro_mult = 1.0 + float( diff --git a/assets/src/ba_data/python/ba/_achievement.py b/assets/src/ba_data/python/ba/_achievement.py index 09445c1b..c024dfbd 100644 --- a/assets/src/ba_data/python/ba/_achievement.py +++ b/assets/src/ba_data/python/ba/_achievement.py @@ -140,7 +140,7 @@ def get_achievement(name: str) -> Achievement: achs = [a for a in _ba.app.achievements if a.name == name] assert len(achs) < 2 if not achs: - raise Exception("Invalid achievement name: '" + name + "'") + raise ValueError("Invalid achievement name: '" + name + "'") return achs[0] @@ -396,7 +396,7 @@ class Achievement: v_attach = Text.VAttach.TOP attach = Image.Attach.TOP_CENTER else: - raise Exception('invalid style "' + style + '"') + raise ValueError('invalid style "' + style + '"') # Attempt to determine what campaign we're in # (so we know whether to show "hard mode only"). diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 9ca5def9..484e1e67 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -729,7 +729,7 @@ class App: if args is None: args = {} if game == '': - raise Exception('empty game name') + raise ValueError('empty game name') campaignname, levelname = game.split(':') campaign = get_campaign(campaignname) levels = campaign.get_levels() diff --git a/assets/src/ba_data/python/ba/_campaign.py b/assets/src/ba_data/python/ba/_campaign.py index 3beb4dca..3932a139 100644 --- a/assets/src/ba_data/python/ba/_campaign.py +++ b/assets/src/ba_data/python/ba/_campaign.py @@ -64,7 +64,7 @@ class Campaign: def add_level(self, level: ba.Level) -> None: """Adds a ba.Level to the Campaign.""" if level.get_campaign() is not None: - raise Exception('level already belongs to a campaign') + raise RuntimeError('level already belongs to a campaign') level.set_campaign(self, len(self._levels)) self._levels.append(level) @@ -73,12 +73,14 @@ class Campaign: return self._levels def get_level(self, name: str) -> ba.Level: + from ba import _error """Return a contained ba.Level by name.""" for level in self._levels: if level.name == name: return level - raise Exception("Level '" + name + "' not found in campaign '" + - self.name + "'") + raise _error.NotFoundError( + "Level '" + name + "' not found in campaign '" + + self.name + "'") def reset(self) -> None: """Reset state for the Campaign.""" @@ -98,7 +100,7 @@ class Campaign: """Return the live config dict for this campaign.""" val: Dict[str, Any] = (_ba.app.config.setdefault('Campaigns', {}).setdefault( - self._name, {})) + self._name, {})) assert isinstance(val, dict) return val diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 764f755a..be5f5450 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -292,7 +292,7 @@ class CoopSession(Session): and self.campaign_state['level'] == 'Onslaught Training' and not app.kiosk_mode): if self._tutorial_activity is None: - raise Exception('tutorial not preloaded properly') + raise RuntimeError('tutorial not preloaded properly') self.set_activity(self._tutorial_activity) self._tutorial_activity = None self._ran_tutorial_activity = True diff --git a/assets/src/ba_data/python/ba/_dependency.py b/assets/src/ba_data/python/ba/_dependency.py index 3cff9850..8ae536dd 100644 --- a/assets/src/ba_data/python/ba/_dependency.py +++ b/assets/src/ba_data/python/ba/_dependency.py @@ -283,7 +283,7 @@ class DependencySet(Generic[T]): # Watch for wacky infinite dep loops. if recursion > 10: - raise Exception('Max recursion reached') + raise RecursionError('Max recursion reached') hashval = dep.get_hash() diff --git a/assets/src/ba_data/python/ba/_error.py b/assets/src/ba_data/python/ba/_error.py index 2f54e07b..42e8cd89 100644 --- a/assets/src/ba_data/python/ba/_error.py +++ b/assets/src/ba_data/python/ba/_error.py @@ -140,7 +140,7 @@ def print_exception(*args: Any, **keywds: Any) -> None: if keywds: allowed_keywds = ['once'] if any(keywd not in allowed_keywds for keywd in keywds): - raise Exception('invalid keyword(s)') + raise TypeError('invalid keyword(s)') try: # If we're only printing once and already have, bail. if keywds.get('once', False): diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index bda98c84..02b34008 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -693,7 +693,7 @@ class GameActivity(Activity[PlayerType, TeamType]): else: sb_desc_l = sb_desc_in if not isinstance(sb_desc_l[0], str): - raise Exception('Invalid format for instance description') + raise TypeError('Invalid format for instance description') is_empty = (sb_desc_l[0] == '') subs = [] @@ -781,7 +781,7 @@ class GameActivity(Activity[PlayerType, TeamType]): else: desc_l = desc_in if not isinstance(desc_l[0], str): - raise Exception('Invalid format for instance description') + raise TypeError('Invalid format for instance description') subs = [] for i in range(len(desc_l) - 1): subs.append(('${ARG' + str(i + 1) + '}', str(desc_l[i + 1]))) diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index 214c837a..61b62458 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -137,7 +137,7 @@ def sharedobj(name: str) -> Any: True), ('modify_part_collision', 'friction', 0.0))) else: - raise Exception( + raise ValueError( "unrecognized shared object (activity context): '" + name + "'") else: @@ -156,10 +156,10 @@ def sharedobj(name: str) -> Any: if name == 'globals': obj = _ba.newnode('sessionglobals') else: - raise Exception('unrecognized shared object ' - "(session context): '" + name + "'") + raise ValueError('unrecognized shared object ' + "(session context): '" + name + "'") else: - raise Exception('no current activity or session context') + raise RuntimeError('no current activity or session context') # Ok, got a shiny new shared obj; store it for quick access next time. sharedobjs[name] = obj @@ -208,7 +208,7 @@ def animate(node: ba.Node, elif timeformat is TimeFormat.MILLISECONDS: mult = 1 else: - raise Exception(f'invalid timeformat value: {timeformat}') + raise ValueError(f'invalid timeformat value: {timeformat}') curve.times = [int(mult * time) for time, val in items] curve.offset = _ba.time(timeformat=TimeFormat.MILLISECONDS) + int( @@ -269,7 +269,7 @@ def animate_array(node: ba.Node, elif timeformat is TimeFormat.MILLISECONDS: mult = 1 else: - raise Exception('invalid timeformat value: "' + str(timeformat) + '"') + raise ValueError('invalid timeformat value: "' + str(timeformat) + '"') for i in range(size): curve = _ba.newnode('animcurve', @@ -390,7 +390,7 @@ def timestring(timeval: float, elif timeformat is TimeFormat.MILLISECONDS: pass else: - raise Exception(f'invalid timeformat: {timeformat}') + raise ValueError(f'invalid timeformat: {timeformat}') if not isinstance(timeval, int): timeval = int(timeval) bits = [] diff --git a/assets/src/ba_data/python/ba/_lang.py b/assets/src/ba_data/python/ba/_lang.py index 73664924..608f7579 100644 --- a/assets/src/ba_data/python/ba/_lang.py +++ b/assets/src/ba_data/python/ba/_lang.py @@ -111,7 +111,7 @@ class Lstr: """ # pylint: disable=too-many-branches if args: - raise Exception('Lstr accepts only keyword arguments') + raise TypeError('Lstr accepts only keyword arguments') # Basically just store the exact args they passed. # However if they passed any Lstr values for subs, @@ -120,7 +120,7 @@ class Lstr: our_type = type(self) if isinstance(self.args.get('value'), our_type): - raise Exception("'value' must be a regular string; not an Lstr") + raise TypeError("'value' must be a regular string; not an Lstr") if 'subs' in self.args: subs_new = [] @@ -301,7 +301,7 @@ def _add_to_attr_dict(dst: AttrDict, src: Dict) -> None: _add_to_attr_dict(dst_dict, value) else: if not isinstance(value, (float, int, bool, str, str, type(None))): - raise Exception("invalid value type for res '" + key + "': " + + raise TypeError("invalid value type for res '" + key + "': " + str(type(value))) dst[key] = value @@ -401,9 +401,10 @@ def get_resource(resource: str, # Ok, looks like we couldn't find our main or fallback resource # anywhere. Now if we've been given a fallback value, return it; # otherwise fail. + from ba import _error if fallback_value is not None: return fallback_value - raise Exception("resource not found: '" + resource + "'") + raise _error.NotFoundError("resource not found: '" + resource + "'") def translate(category: str, @@ -466,5 +467,5 @@ def is_custom_unicode_char(char: str) -> bool: """Return whether a char is in the custom unicode range we use.""" assert isinstance(char, str) if len(char) != 1: - raise Exception('Invalid Input; must be length 1') + raise ValueError('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 f6471028..8f59099a 100644 --- a/assets/src/ba_data/python/ba/_level.py +++ b/assets/src/ba_data/python/ba/_level.py @@ -169,7 +169,7 @@ class Level: can be modified in place.""" campaign = self.get_campaign() if campaign is None: - raise Exception('level is not in a campaign') + raise TypeError('level is not in a campaign') campaign_config = campaign.get_config_dict() val: Dict[str, Any] = campaign_config.setdefault(self._name, { diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index ac7971ee..30a08245 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -353,7 +353,8 @@ class Chooser: """The chooser's ba.Lobby.""" lobby = self._lobby() if lobby is None: - raise Exception('Lobby does not exist.') + from ba import _error + raise _error.NotFoundError('Lobby does not exist.') return lobby def get_lobby(self) -> Optional[ba.Lobby]: diff --git a/assets/src/ba_data/python/ba/_map.py b/assets/src/ba_data/python/ba/_map.py index 0d5fce1c..e60d90b2 100644 --- a/assets/src/ba_data/python/ba/_map.py +++ b/assets/src/ba_data/python/ba/_map.py @@ -144,7 +144,8 @@ def get_map_class(name: str) -> Type[ba.Map]: try: return _ba.app.maps[name] except Exception: - raise Exception("Map not found: '" + name + "'") + from ba import _error + raise _error.NotFoundError("Map not found: '" + name + "'") class Map(Actor): @@ -218,9 +219,11 @@ class Map(Actor): try: self.preloaddata = _ba.getactivity().preloads[type(self)] except Exception: - raise Exception('Preload data not found for ' + str(type(self)) + - '; make sure to call the type\'s preload()' - ' staticmethod in the activity constructor') + from ba import _error + raise _error.NotFoundError( + 'Preload data not found for ' + str(type(self)) + + '; make sure to call the type\'s preload()' + ' staticmethod in the activity constructor') # Set various globals. gnode = _gameutils.sharedobj('globals') @@ -339,7 +342,7 @@ class Map(Actor): point_list.append(pts) else: if len(pts) != 3: - raise Exception('invalid point') + raise ValueError('invalid point') point_list.append(pts + (0, 0, 0)) i += 1 return point_list @@ -354,7 +357,7 @@ class Map(Actor): return pnt def get_ffa_start_position( - self, players: Sequence[ba.Player]) -> Sequence[float]: + self, players: Sequence[ba.Player]) -> Sequence[float]: """Return a random starting position in one of the FFA spawn areas. If a list of ba.Players is provided; the returned points will be @@ -428,5 +431,5 @@ class Map(Actor): def register_map(maptype: Type[Map]) -> None: """Register a map class with the game.""" if maptype.name in _ba.app.maps: - raise Exception('map "' + maptype.name + '" already registered') + raise RuntimeError('map "' + maptype.name + '" already registered') _ba.app.maps[maptype.name] = maptype diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index 6aa52847..ec256e8e 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -326,7 +326,7 @@ def get_scan_results() -> ScanResults: while app.metascan is None: time.sleep(0.05) if time.time() - starttime > 10.0: - raise Exception('timeout waiting for meta scan to complete.') + raise TimeoutError('timeout waiting for meta scan to complete.') return app.metascan diff --git a/assets/src/ba_data/python/ba/_music.py b/assets/src/ba_data/python/ba/_music.py index c1bd2524..a1962adb 100644 --- a/assets/src/ba_data/python/ba/_music.py +++ b/assets/src/ba_data/python/ba/_music.py @@ -191,7 +191,7 @@ class MusicController: """Returns the system music player, instantiating if necessary.""" if self._music_player is None: if self._music_player_type is None: - raise Exception('no music player type set') + raise TypeError('no music player type set') self._music_player = self._music_player_type() return self._music_player @@ -248,20 +248,21 @@ class MusicController: and isinstance(entry['name'], str)): entry_type = entry['type'] else: - raise Exception('invalid soundtrack entry: ' + str(entry) + + raise TypeError('invalid soundtrack entry: ' + str(entry) + ' (type ' + str(type(entry)) + ')') if self.supports_soundtrack_entry_type(entry_type): return entry_type - raise Exception('invalid soundtrack entry:' + str(entry)) - except Exception as exc: - print('EXC on get_soundtrack_entry_type', exc) + raise ValueError('invalid soundtrack entry:' + str(entry)) + except Exception: + from ba import _error + _error.print_exception() return 'default' def get_soundtrack_entry_name(self, entry: Any) -> str: """Given a soundtrack entry, returns its name.""" try: if entry is None: - raise Exception('entry is None') + raise TypeError('entry is None') # Simple string denotes an iTunesPlaylist name (legacy entry). if isinstance(entry, str): @@ -272,7 +273,7 @@ class MusicController: and isinstance(entry['type'], str) and 'name' in entry and isinstance(entry['name'], str)): return entry['name'] - raise Exception('invalid soundtrack entry:' + str(entry)) + raise ValueError('invalid soundtrack entry:' + str(entry)) except Exception: from ba import _error _error.print_exception() diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index 4087874b..d7a7b371 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -56,7 +56,7 @@ def get_ip_address_type(addr: str) -> socket.AddressFamily: except OSError: pass if socket_type is None: - raise Exception('addr seems to be neither v4 or v6: ' + str(addr)) + raise ValueError('addr seems to be neither v4 or v6: ' + str(addr)) return socket_type @@ -76,7 +76,7 @@ class ServerCallThread(threading.Thread): self._request = request self._request_type = request_type if not isinstance(response_type, ServerResponseType): - raise Exception(f'Invalid response type: {response_type}') + raise TypeError(f'Invalid response type: {response_type}') self._response_type = response_type self._data = {} if data is None else copy.deepcopy(data) self._callback: Optional[ServerCallbackType] = callback @@ -128,7 +128,7 @@ class ServerCallThread(threading.Thread): parse.urlencode(self._data).encode(), {'User-Agent': _ba.app.user_agent_string})) else: - raise Exception('Invalid request_type: ' + self._request_type) + raise TypeError('Invalid request_type: ' + self._request_type) # If html request failed. if response.getcode() != 200: @@ -144,7 +144,7 @@ class ServerCallThread(threading.Thread): raw_data_s = raw_data.decode() response_data = json.loads(raw_data_s) else: - raise Exception(f'invalid responsetype: {self._response_type}') + raise TypeError(f'invalid responsetype: {self._response_type}') except (urllib.error.URLError, ConnectionError): # Server rejected us, broken pipe, etc. It happens. Ignoring. response_data = None diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 56e490e9..be51c669 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -181,7 +181,7 @@ class Player(Generic[TeamType]): self._sessionplayer.reset_input() def __bool__(self) -> bool: - return self._sessionplayer.exists() + return self.exists() def playercast(totype: Type[PlayerType], player: ba.Player) -> PlayerType: diff --git a/assets/src/ba_data/python/ba/_playlist.py b/assets/src/ba_data/python/ba/_playlist.py index 1786ee21..22c18c1b 100644 --- a/assets/src/ba_data/python/ba/_playlist.py +++ b/assets/src/ba_data/python/ba/_playlist.py @@ -80,7 +80,7 @@ def filter_playlist(playlist: PlaylistType, # the actual game class. add successful ones to our initial list # to present to the user. if not isinstance(entry['type'], str): - raise Exception('invalid entry format') + raise TypeError('invalid entry format') try: # Do some type filters for backwards compat. if entry['type'] in ('Assault.AssaultGame', diff --git a/assets/src/ba_data/python/ba/_store.py b/assets/src/ba_data/python/ba/_store.py index 262ddeee..09e27e01 100644 --- a/assets/src/ba_data/python/ba/_store.py +++ b/assets/src/ba_data/python/ba/_store.py @@ -56,7 +56,7 @@ def get_store_item_name_translated(item_name: str) -> ba.Lstr: return gametype.get_display_string() if item_name.startswith('icons.'): return _lang.Lstr(resource='editProfileWindow.iconText') - raise Exception('unrecognized item: ' + item_name) + raise ValueError('unrecognized item: ' + item_name) def get_store_item_display_size(item_name: str) -> Tuple[float, float]: diff --git a/assets/src/ba_data/python/ba/ui/__init__.py b/assets/src/ba_data/python/ba/ui/__init__.py index d1745291..58e7a43e 100644 --- a/assets/src/ba_data/python/ba/ui/__init__.py +++ b/assets/src/ba_data/python/ba/ui/__init__.py @@ -127,7 +127,7 @@ class UIEntry: if self._name == 'mainmenu': from bastd.ui import mainmenu return cast(Type[UILocation], mainmenu.MainMenuWindow) - raise Exception('unknown ui class ' + str(self._name)) + raise ValueError('unknown ui class ' + str(self._name)) class UIController: @@ -192,7 +192,7 @@ def uicleanupcheck(obj: Any, widget: ba.Widget) -> None: if DEBUG_UI_CLEANUP_CHECKS: print(f'adding uicleanup to {obj}') if not isinstance(widget, _ba.Widget): - raise Exception('widget arg is not a ba.Widget') + raise TypeError('widget arg is not a ba.Widget') def foobar() -> None: """Just testing."""