From 47ca132c33f65071901340cde9c860583a018292 Mon Sep 17 00:00:00 2001
From: Eric Froemling
Date: Sat, 31 Oct 2020 16:15:05 -0500
Subject: [PATCH] Addressed some dependency loop issues
---
.efrocachemap | 32 ++++++++---------
.idea/dictionaries/ericf.xml | 1 +
assets/src/ba_data/python/ba/__init__.py | 2 +-
assets/src/ba_data/python/ba/_apputils.py | 22 ++++++++----
assets/src/ba_data/python/ba/_general.py | 28 +++++++++++----
assets/src/ba_data/python/ba/_session.py | 2 +-
assets/src/ba_data/python/ba/ui/__init__.py | 5 ++-
.../ba_data/python/bastd/ui/coop/browser.py | 4 +++
.../python/bastd/ui/gather/__init__.py | 36 +++++++++----------
.../python/bastd/ui/gather/manualtab.py | 6 ++++
.../ba_data/python/bastd/ui/store/browser.py | 7 ++++
assets/src/ba_data/python/bastd/ui/watch.py | 12 +++++++
.../.idea/dictionaries/ericf.xml | 4 +--
docs/ba_module.md | 15 +++++++-
src/ballistica/ballistica.cc | 2 +-
src/ballistica/python/python.h | 2 +-
src/generated_src/ballistica/binding.py | 2 +-
17 files changed, 126 insertions(+), 56 deletions(-)
diff --git a/.efrocachemap b/.efrocachemap
index 1bda2c16..90f2648f 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -3932,24 +3932,24 @@
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
- "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/71/6b45cf5a4a3ed2c2f21853dd4ef5",
- "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8a/f5/60056a8ded058f143929f50aad4d",
- "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8f/87/5297d9be37d6faed52315a4098b6",
- "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/8e/418f87c669cbef6b031e84caa24f",
- "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/c3/17bd74632240ce445290ad1d1e6b",
- "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/13/5c/59fad7dcebaf88a92372b54ef35d",
- "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/41/10ddaf61d0199cf19764b365233d",
- "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0c/62/1d6189df26dbc8293ccceae1763d",
- "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d3/1f/5944ecb4991c8c7bbcf4cc5b28e8",
- "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a1/bc/9ac66ab00360dd4c9353e67fdabf",
- "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e0/eb/0de6c758f379fc4d12ec30ed3e79",
- "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/33/ca/c57c3668af1215c22fc29a52dd4f",
+ "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f4/dc/e060b50e18cf9ea793a8024c71ea",
+ "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8c/ba/6ff3079ed32a9bcf0b19ffdd5014",
+ "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/91/f9/fb6d662e6a5b517405e952cebb47",
+ "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/bb/a249dad07ac24d901e263d4728ce",
+ "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/39/9484a05296f6c1815f48a19f7f80",
+ "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ce/13/3d5a5634dc85a9fff77f40eea079",
+ "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/64/a5/49ea3e527d625ec9891ac2d8dde8",
+ "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/13/c626103f654d4f30156b6440b547",
+ "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/33/ce/f6ce9603a9f24fa46363c19b0995",
+ "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/80/72/6844abdad72330180d9401023729",
+ "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d6/db/e9ca1e2278872e8d49614597ca41",
+ "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/07/66/1eb6b6a7141a2d6a9a9dcb12573e",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c3/d7/627d518a92951cf7fe9fc0b9b3a0",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/de/49/2cfc34ac856737d903954db5571b",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e8/9a/67cf9ece361ca2f5d338009bdbfc",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/86/de/7d9c9a2b7bba34c630130ed759c9",
- "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/28/7e/3aa3d21bb007a3fd44fee67d03e2",
- "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/47/46/9a4ad3c7200e90fb58861ede9900",
- "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3c/50/c9941b2059c3783861a6093f71a9",
- "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/72/d9/4b66bf3eb0e3d0aa2e53de8d07e8"
+ "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3f/20/a97fd2c5fd3a3f0332e4a822c112",
+ "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d6/d2/6e5f87b787c1a33a3c1947f589e1",
+ "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a6/b6/e09b9690415a84f0602db60ef4de",
+ "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f0/f1/aa367945b9b426569dd8372a565e"
}
\ No newline at end of file
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index c695c388..94a8a102 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -637,6 +637,7 @@
evel
eventid
ewww
+ ewwww
excludepowerups
excludetypes
excstr
diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py
index b4a0c97b..8e3a6e9f 100644
--- a/assets/src/ba_data/python/ba/__init__.py
+++ b/assets/src/ba_data/python/ba/__init__.py
@@ -55,7 +55,7 @@ from ba._dualteamsession import DualTeamSession
from ba._achievement import Achievement, AchievementSubsystem
from ba._appconfig import AppConfig
from ba._appdelegate import AppDelegate
-from ba._apputils import is_browser_likely_available
+from ba._apputils import is_browser_likely_available, garbage_collect
from ba._campaign import Campaign
from ba._gameutils import (GameTip, animate, animate_array, show_damage_count,
timestring, cameraflash)
diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py
index 422c2813..f3698a4e 100644
--- a/assets/src/ba_data/python/ba/_apputils.py
+++ b/assets/src/ba_data/python/ba/_apputils.py
@@ -3,6 +3,7 @@
"""Utility functionality related to the overall operation of the app."""
from __future__ import annotations
+import gc
import os
from typing import TYPE_CHECKING
@@ -150,9 +151,8 @@ def handle_leftover_log_file() -> None:
_error.print_exception('Error handling leftover log file.')
-def garbage_collect(session_end: bool = True) -> None:
- """Run an explicit pass of garbage collection."""
- import gc
+def garbage_collect_session_end() -> None:
+ """Run explicit garbage collection with extra checks for session end."""
gc.collect()
# Can be handy to print this to check for leaks between games.
@@ -162,8 +162,19 @@ def garbage_collect(session_end: bool = True) -> None:
print('PYTHON GC FOUND', len(gc.garbage), 'UNCOLLECTIBLE OBJECTS:')
for i, obj in enumerate(gc.garbage):
print(str(i) + ':', obj)
- if session_end:
- print_live_object_warnings('after session shutdown')
+ print_live_object_warnings('after session shutdown')
+
+
+def garbage_collect() -> None:
+ """Run an explicit pass of garbage collection.
+
+ category: General Utility Functions
+
+ May also print warnings/etc. if collection takes too long or if
+ uncollectible objects are found (so use this instead of simply
+ gc.collect().
+ """
+ gc.collect()
def print_live_object_warnings(when: Any,
@@ -171,7 +182,6 @@ def print_live_object_warnings(when: Any,
ignore_activity: ba.Activity = None) -> None:
"""Print warnings for remaining objects in the current context."""
# pylint: disable=cyclic-import
- import gc
from ba._session import Session
from ba._actor import Actor
from ba._activity import Activity
diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py
index c88ffa19..a4ad9fdb 100644
--- a/assets/src/ba_data/python/ba/_general.py
+++ b/assets/src/ba_data/python/ba/_general.py
@@ -299,6 +299,27 @@ def verify_object_death(obj: object) -> None:
timetype=TimeType.REAL)
+def print_active_refs(obj: Any) -> None:
+ """Print info about things referencing a given object.
+
+ Category: General Utility Functions
+
+ Useful for tracking down cyclical references and causes for zombie objects.
+ """
+ from types import FrameType
+ refs = list(gc.get_referrers(obj))
+ print(f'{Clr.YLW}Active referrers to {obj}:{Clr.RST}')
+ for i, ref in enumerate(refs):
+ print(f'{Clr.YLW}#{i+1}:{Clr.BLU} {ref}{Clr.RST}')
+ # For certain types of objects such as stack frames, show what is
+ # keeping *them* alive too.
+ if isinstance(ref, FrameType):
+ print(f'{Clr.YLW} Active referrers to #{i+1}:{Clr.RST}')
+ refs2 = list(gc.get_referrers(ref))
+ for j, ref2 in enumerate(refs2):
+ print(f'{Clr.YLW} #{j+1}:{Clr.BLU} {ref2}{Clr.RST}')
+
+
def _verify_object_death(wref: ReferenceType) -> None:
obj = wref()
if obj is None:
@@ -312,12 +333,7 @@ def _verify_object_death(wref: ReferenceType) -> None:
print(f'{Clr.RED}Error: {name} not dying'
f' when expected to: {Clr.BLD}{obj}{Clr.RST}')
- refs = list(gc.get_referrers(obj))
- print(f'{Clr.YLW}Active References:{Clr.RST}')
- i = 1
- for ref in refs:
- print(f'{Clr.YLW} reference {i}:{Clr.BLU} {ref}{Clr.RST}')
- i += 1
+ print_active_refs(obj)
def storagename(suffix: str = None) -> str:
diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py
index 758b2333..fbed5f85 100644
--- a/assets/src/ba_data/python/ba/_session.py
+++ b/assets/src/ba_data/python/ba/_session.py
@@ -618,7 +618,7 @@ class Session:
# to run garbage collection to clear out any circular dependency
# loops. We keep this disabled normally to avoid non-deterministic
# hitches.
- garbage_collect(session_end=False)
+ garbage_collect()
with _ba.Context(self):
if can_show_ad_on_death:
diff --git a/assets/src/ba_data/python/ba/ui/__init__.py b/assets/src/ba_data/python/ba/ui/__init__.py
index 2907950c..22157577 100644
--- a/assets/src/ba_data/python/ba/ui/__init__.py
+++ b/assets/src/ba_data/python/ba/ui/__init__.py
@@ -11,6 +11,7 @@ from typing import TYPE_CHECKING, cast, Type
import _ba
from ba._enums import TimeType
+from ba._general import print_active_refs
if TYPE_CHECKING:
from typing import Optional, List, Any
@@ -216,7 +217,9 @@ def ui_upkeep() -> None:
print(
'WARNING:', obj,
'is still alive 5 second after its widget died;'
- ' you probably have a memory leak.')
+ ' you might have a memory leak.')
+ print_active_refs(obj)
+
else:
remainingchecks.append(check)
ui.cleanupchecks = remainingchecks
diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py
index a09f4f54..c9867e80 100644
--- a/assets/src/ba_data/python/bastd/ui/coop/browser.py
+++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py
@@ -285,6 +285,10 @@ class CoopBrowserWindow(ba.Window):
import bastd.ui.play as _unused10
def _update(self) -> None:
+ # Do nothing if we've somehow outlived our actual UI.
+ if not self._root_widget:
+ return
+
cur_time = ba.time(ba.TimeType.REAL)
# If its been a while since we got a tournament update, consider the
diff --git a/assets/src/ba_data/python/bastd/ui/gather/__init__.py b/assets/src/ba_data/python/bastd/ui/gather/__init__.py
index 201e729f..7fb255a6 100644
--- a/assets/src/ba_data/python/bastd/ui/gather/__init__.py
+++ b/assets/src/ba_data/python/bastd/ui/gather/__init__.py
@@ -240,7 +240,6 @@ class GatherWindow(ba.Window):
ba.print_exception(f'Error saving state for {self}.')
def _restore_state(self) -> None:
- # pylint: disable=too-many-branches
try:
for tab in self._tabs.values():
tab.restore_state()
@@ -251,24 +250,17 @@ class GatherWindow(ba.Window):
assert isinstance(sel_name, (str, type(None)))
current_tab = self.TabID.ABOUT
gather_tab_val = ba.app.config.get('Gather Tab')
-
- if bool(False):
- # EWWW: normally would just do this, but it seems to result in
- # a reference to self sticking around somewhere. (presumably
- # in the exception?). Should get to the bottom of this.
- try:
- stored_tab = self.TabID(gather_tab_val)
- if stored_tab in self._tab_row.tabs:
- current_tab = stored_tab
- except ValueError:
- pass
- else:
- # Falling back to this for now.
- tab_vals = {t.value for t in self.TabID}
- if gather_tab_val in tab_vals:
- stored_tab = self.TabID(gather_tab_val)
- if stored_tab in self._tab_row.tabs:
- current_tab = stored_tab
+ try:
+ stored_tab = self.TabID(gather_tab_val)
+ if stored_tab in self._tab_row.tabs:
+ current_tab = stored_tab
+ except ValueError:
+ # EWWWW; this exception causes a dependency loop that won't
+ # go away until the next cyclical collection, which can
+ # keep us alive. Perhaps should rethink our garbage
+ # collection strategy, but for now just explicitly running
+ # a cycle.
+ ba.pushcall(ba.garbage_collect)
self._set_tab(current_tab)
if sel_name == 'Back':
sel = self._back_button
@@ -279,6 +271,12 @@ class GatherWindow(ba.Window):
sel_tab_id = self.TabID(sel_name.split(':')[-1])
except ValueError:
sel_tab_id = self.TabID.ABOUT
+ # EWWWW; this exception causes a dependency loop that won't
+ # go away until the next cyclical collection, which can
+ # keep us alive. Perhaps should rethink our garbage
+ # collection strategy, but for now just explicitly running
+ # a cycle.
+ ba.pushcall(ba.garbage_collect)
sel = self._tab_row.tabs[sel_tab_id].button
else:
sel = self._tab_row.tabs[current_tab].button
diff --git a/assets/src/ba_data/python/bastd/ui/gather/manualtab.py b/assets/src/ba_data/python/bastd/ui/gather/manualtab.py
index 64c0c2e3..45dbb22f 100644
--- a/assets/src/ba_data/python/bastd/ui/gather/manualtab.py
+++ b/assets/src/ba_data/python/bastd/ui/gather/manualtab.py
@@ -184,6 +184,12 @@ class ManualGatherTab(GatherTab):
try:
port = int(cast(str, ba.textwidget(query=port_textwidget)))
except ValueError:
+ # EWWWW; this exception causes a dependency loop that won't
+ # go away until the next cyclical collection, which can
+ # keep us alive. Perhaps should rethink our garbage
+ # collection strategy, but for now just explicitly running
+ # a cycle.
+ ba.pushcall(ba.garbage_collect)
port = -1
if port > 65535 or port < 0:
ba.screenmessage(ba.Lstr(resource='internal.invalidPortErrorText'),
diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py
index 12be6a00..3067dabc 100644
--- a/assets/src/ba_data/python/bastd/ui/store/browser.py
+++ b/assets/src/ba_data/python/bastd/ui/store/browser.py
@@ -1028,6 +1028,13 @@ class StoreBrowserWindow(ba.Window):
current_tab = self.TabID(ba.app.config.get('Store Tab'))
except ValueError:
current_tab = self.TabID.CHARACTERS
+
+ # EWWWW; this exception causes a dependency loop that won't
+ # go away until the next cyclical collection, which can keep
+ # us alive. Perhaps should rethink our garbage collection
+ # strategy, but for now just explicitly running a cycle.
+ ba.pushcall(ba.garbage_collect)
+
if self._show_tab is not None:
current_tab = self._show_tab
if sel_name == 'GetTickets' and self._get_tickets_button:
diff --git a/assets/src/ba_data/python/bastd/ui/watch.py b/assets/src/ba_data/python/bastd/ui/watch.py
index 011932f1..f27a1819 100644
--- a/assets/src/ba_data/python/bastd/ui/watch.py
+++ b/assets/src/ba_data/python/bastd/ui/watch.py
@@ -511,6 +511,12 @@ class WatchWindow(ba.Window):
try:
current_tab = self.TabID(ba.app.config.get('Watch Tab'))
except ValueError:
+ # EWWWW; this exception causes a dependency loop that won't
+ # go away until the next cyclical collection, which can
+ # keep us alive. Perhaps should rethink our garbage
+ # collection strategy, but for now just explicitly running
+ # a cycle.
+ ba.pushcall(ba.garbage_collect)
current_tab = self.TabID.MY_REPLAYS
self._set_tab(current_tab)
@@ -522,6 +528,12 @@ class WatchWindow(ba.Window):
try:
sel_tab_id = self.TabID(sel_name.split(':')[-1])
except ValueError:
+ # EWWWW; this exception causes a dependency loop that won't
+ # go away until the next cyclical collection, which can
+ # keep us alive. Perhaps should rethink our garbage
+ # collection strategy, but for now just explicitly running
+ # a cycle.
+ ba.pushcall(ba.garbage_collect)
sel_tab_id = self.TabID.MY_REPLAYS
sel = self._tab_row.tabs[sel_tab_id].button
else:
diff --git a/ballisticacore-cmake/.idea/dictionaries/ericf.xml b/ballisticacore-cmake/.idea/dictionaries/ericf.xml
index 3f1bbe00..de0b1de7 100644
--- a/ballisticacore-cmake/.idea/dictionaries/ericf.xml
+++ b/ballisticacore-cmake/.idea/dictionaries/ericf.xml
@@ -13,8 +13,8 @@
ack'ed
acked
acks
- aclass
aclass's
+ aclass
activityplayer
addrs
adjoint
@@ -146,8 +146,8 @@
cmath
cmds
cmdvals
- codewarrior
codewarrior's
+ codewarrior
cofnodes
collapseable
collidable
diff --git a/docs/ba_module.md b/docs/ba_module.md
index aad98319..25a9627a 100644
--- a/docs/ba_module.md
+++ b/docs/ba_module.md
@@ -1,5 +1,5 @@
-last updated on 2020-10-29 for Ballistica version 1.5.27 build 20234
+last updated on 2020-10-31 for Ballistica version 1.5.27 build 20236
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!
@@ -86,6 +86,7 @@
+
+garbage_collect() -> None
+
+Run an explicit pass of garbage collection.
+
+Category: General Utility Functions
+
+May also print warnings/etc. if collection takes too long or if
+uncollectible objects are found (so use this instead of simply
+gc.collect().
+
getactivity(doraise: bool = True) -> <varies>
diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc
index 54d00eec..0e330474 100644
--- a/src/ballistica/ballistica.cc
+++ b/src/ballistica/ballistica.cc
@@ -21,7 +21,7 @@
namespace ballistica {
// These are set automatically via script; don't change here.
-const int kAppBuildNumber = 20235;
+const int kAppBuildNumber = 20236;
const char* kAppVersion = "1.5.27";
// Our standalone globals.
diff --git a/src/ballistica/python/python.h b/src/ballistica/python/python.h
index 78985b75..8f467266 100644
--- a/src/ballistica/python/python.h
+++ b/src/ballistica/python/python.h
@@ -268,7 +268,7 @@ class Python {
kTranslateCall,
kLStrClass,
kCallClass,
- kGarbageCollectCall,
+ kGarbageCollectSessionEndCall,
kConfig,
kOnAppLaunchCall,
kClientInfoQueryResponseCall,
diff --git a/src/generated_src/ballistica/binding.py b/src/generated_src/ballistica/binding.py
index c3742f4d..1102dcd4 100644
--- a/src/generated_src/ballistica/binding.py
+++ b/src/generated_src/ballistica/binding.py
@@ -103,7 +103,7 @@ def get_binding_values() -> object:
ba.app.lang.translate, # kTranslateCall
ba.Lstr, # kLStrClass
ba.Call, # kCallClass
- _apputils.garbage_collect, # kGarbageCollectCall
+ _apputils.garbage_collect_session_end, # kGarbageCollectSessionEndCall
ba.ContextError, # kContextError
ba.NotFoundError, # kNotFoundError
ba.NodeNotFoundError, # kNodeNotFoundError