diff --git a/.efrocachemap b/.efrocachemap index 175a3c7f..17968523 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4099,48 +4099,48 @@ "build/assets/windows/Win32/ucrtbased.dll": "bfd1180c269d3950b76f35a63655e9e1", "build/assets/windows/Win32/vc_redist.x86.exe": "15a5f1f876503885adbdf5b3989b3718", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "f2b4a48180ab14d238b41e1530381393", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "e89a3f4680e8800f94a47ba00fda82e9", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "9e58df7e8dc622d0e07bcc2e5e01980b", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "76e0ee141fc138b015e466b876ca5c40", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "dc69ff22b10a69bd68551921e80e6d4f", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "382f41634994e64aef25cbd89ad30608", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "99b67d89e72156fecf82728f3ca9023e", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "9e123048c9a937623bf8a9049fe52a68", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "0bb1ebf96216318b97f624ca01515319", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "fe741b2e775639b715245a6397ce0f01", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "463e5220f0987196df4b74433eb6b533", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "fcdcc5a4214eff648234f0f6ad8db286", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "71eb60bca0efb35b5519359f32701ef0", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "4409110d1107f9ec6ea314574b963092", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "8287610eeae417260ef3891d09526366", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "07783dd9ef83a4417d9e7b8769e704e1", - "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "9f68628128b83900865751c347964c77", - "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "0ad4775fc4ff5cd2e3b63ecf7823daa4", - "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "9f68628128b83900865751c347964c77", - "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "0ad4775fc4ff5cd2e3b63ecf7823daa4", - "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "087b7eec0a029b66b957bce579c9ebbd", - "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "46a360165efa06de3e5d562c5daddddb", - "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "087b7eec0a029b66b957bce579c9ebbd", - "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "46a360165efa06de3e5d562c5daddddb", - "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "28b13d45428184f0715565c54f23b115", - "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "41f933cc9a7c6cb748ff2fb0d5237b4d", - "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "28b13d45428184f0715565c54f23b115", - "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "41f933cc9a7c6cb748ff2fb0d5237b4d", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "d31f476fe2587f891662739d5cf66498", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "42d34950f26b92cf25b190868f53a20f", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "98912594ab71b0f9f64a24e8234b7a6a", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "7475905e88c2a39f34c4bd216b9efffd", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "d9ceb775128672c17f00e2b2c01c6e4e", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "5546313b197639b7ec6d02a69297ef26", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "4f0e09828aaa10b9a5ad9693ecc9d269", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "028fdd9f3d6434b2779f94eafc6f82f1", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "31d6ac3cce2b7d2a38555ad54e6f1b42", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "021d06fb3c8b2963306ebe0602b7c91b", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "41c85f9bdc2e042e502ce23c4faf082d", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "6b3e752d93ee5aa06a738c58f96e3e98", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "4928e07ec24903103f69cf25f1969dce", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "6a70b3e614c3fa0869af93c2620997b4", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "987153b6539715573fe87b8f6675366d", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "130bbcc6e253ea27d580bbec0da23ffb", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "d0ca3125ba2aa6933dc1ed74856e67e4", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "f582343e05c4316af68950f33d9189ea", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "cb8a142b86c07e3e19b27339f7760697", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "1e8480010c07972b2b97f8f0dd5a557e", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "a6201b97f6d36164843c12fb064e4e14", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "d999ef97283b39c844f848d6fa0f56ce", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "22aad71eb4295c6d9d0bf216014a78a7", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "b1f33f4492547b97b9f5f42b3be83524", + "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "9d953b981a1ccf4623a6947ee9bafde7", + "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "b7d3fd701b31ec1b624606e1ca42e4bb", + "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "9d953b981a1ccf4623a6947ee9bafde7", + "build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "b7d3fd701b31ec1b624606e1ca42e4bb", + "build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "2141f1d64ea3eadac63e6e95c517b751", + "build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "5d04a19962d612f977200e27b194f560", + "build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "2141f1d64ea3eadac63e6e95c517b751", + "build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "5d04a19962d612f977200e27b194f560", + "build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "d0a989e1650ba8e19ac7f661355ca7cd", + "build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "a2ebc84706ed89c1558f3171e985a959", + "build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "d0a989e1650ba8e19ac7f661355ca7cd", + "build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "a2ebc84706ed89c1558f3171e985a959", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "365ff249753d35076b02ae97b2aaa203", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "eb0ec0c8e8ea0f87a91980909252330f", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "b525d2fd7b406faf76846aae763c4c24", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "851b26948af977fc31285e5ebd443f6a", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "790cc46a5ad2478eb11148a3748db84a", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "7d70ea7fd9992b3f54372ce0126418c2", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "bdcedd07d700c15dda2f9cd616d50db3", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "4d79e3979dbe6c45eb7a2921a0a116bb", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", "src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad", "src/ballistica/base/mgen/pyembed/binding_base.inc": "3a583e7e03bd4907b21adc3bf5729d15", "src/ballistica/base/mgen/pyembed/binding_base_app.inc": "f0f9dc33ecd4ef7a384f131d62c96c97", "src/ballistica/classic/mgen/pyembed/binding_classic.inc": "3ceb412513963f0818ab39c58bf292e3", - "src/ballistica/core/mgen/pyembed/binding_core.inc": "02bf828e423d0fced4d87aa74f25cbdc", + "src/ballistica/core/mgen/pyembed/binding_core.inc": "aa91582493f32d54825d0c8bc007a902", "src/ballistica/core/mgen/pyembed/env.inc": "f015d726b44d2922112fc14d9f146d8b", "src/ballistica/core/mgen/python_modules_monolithic.h": "fb967ed1c7db0c77d8deb4f00a7103c5", "src/ballistica/scene_v1/mgen/pyembed/binding_scene_v1.inc": "c25b263f2a31fb5ebe057db07d144879", diff --git a/CHANGELOG.md b/CHANGELOG.md index 480e8ed4..bd9c6b54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.37 (build 22105, api 9, 2024-11-19) +### 1.7.37 (build 22106, api 9, 2024-11-22) - Bumping api version to 9. As you'll see below, there's some UI changes that will require a bit of work for any UI mods to adapt to. If your mods don't touch UI stuff at all you can simply bump your api version and call it a day. diff --git a/src/assets/.asset_manifest_public.json b/src/assets/.asset_manifest_public.json index 062e1a90..0da9d678 100644 --- a/src/assets/.asset_manifest_public.json +++ b/src/assets/.asset_manifest_public.json @@ -22,6 +22,7 @@ "ba_data/python/babase/__pycache__/_general.cpython-312.opt-1.pyc", "ba_data/python/babase/__pycache__/_hooks.cpython-312.opt-1.pyc", "ba_data/python/babase/__pycache__/_language.cpython-312.opt-1.pyc", + "ba_data/python/babase/__pycache__/_logging.cpython-312.opt-1.pyc", "ba_data/python/babase/__pycache__/_login.cpython-312.opt-1.pyc", "ba_data/python/babase/__pycache__/_math.cpython-312.opt-1.pyc", "ba_data/python/babase/__pycache__/_meta.cpython-312.opt-1.pyc", @@ -52,6 +53,7 @@ "ba_data/python/babase/_general.py", "ba_data/python/babase/_hooks.py", "ba_data/python/babase/_language.py", + "ba_data/python/babase/_logging.py", "ba_data/python/babase/_login.py", "ba_data/python/babase/_math.py", "ba_data/python/babase/_meta.py", diff --git a/src/assets/Makefile b/src/assets/Makefile index 373602dd..41763c73 100644 --- a/src/assets/Makefile +++ b/src/assets/Makefile @@ -185,6 +185,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ $(BUILD_DIR)/ba_data/python/babase/_general.py \ $(BUILD_DIR)/ba_data/python/babase/_hooks.py \ $(BUILD_DIR)/ba_data/python/babase/_language.py \ + $(BUILD_DIR)/ba_data/python/babase/_logging.py \ $(BUILD_DIR)/ba_data/python/babase/_login.py \ $(BUILD_DIR)/ba_data/python/babase/_math.py \ $(BUILD_DIR)/ba_data/python/babase/_meta.py \ @@ -464,6 +465,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_general.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_hooks.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_language.cpython-312.opt-1.pyc \ + $(BUILD_DIR)/ba_data/python/babase/__pycache__/_logging.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_login.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_math.cpython-312.opt-1.pyc \ $(BUILD_DIR)/ba_data/python/babase/__pycache__/_meta.cpython-312.opt-1.pyc \ diff --git a/src/assets/ba_data/python/babase/__init__.py b/src/assets/ba_data/python/babase/__init__.py index f53b374d..d2d2f4c0 100644 --- a/src/assets/ba_data/python/babase/__init__.py +++ b/src/assets/ba_data/python/babase/__init__.py @@ -17,15 +17,14 @@ a more focused way. # dependency loops. The exception is TYPE_CHECKING blocks and # annotations since those aren't evaluated at runtime. -import logging from efro.util import set_canonical_module_names - import _babase from _babase import ( add_clean_frame_callback, allows_ticket_sales, android_get_external_files_dir, + app_instance_uuid, appname, appnameupper, apptime, @@ -114,6 +113,7 @@ from _babase import ( unlock_all_input, update_internal_logger_levels, user_agent_string, + user_ran_commands, Vec3, workspaces_in_use, ) @@ -172,10 +172,9 @@ from babase._general import ( get_type_name, ) from babase._language import Lstr, LanguageSubsystem +from babase._logging import balog, lifecyclelog from babase._login import LoginAdapter, LoginInfo -# noinspection PyProtectedMember -# (PyCharm inspection bug?) from babase._mgen.enums import ( Permission, SpecialChar, @@ -190,8 +189,6 @@ from babase._plugin import PluginSpec, Plugin, PluginSubsystem from babase._stringedit import StringEditAdapter, StringEditSubsystem from babase._text import timestring -# Our standard set of loggers. -balog = logging.getLogger('ba') _babase.app = app = App() app.postinit() @@ -213,6 +210,7 @@ __all__ = [ 'AppIntentDefault', 'AppIntentExec', 'AppMode', + 'app_instance_uuid', 'appname', 'appnameupper', 'AppModeSelector', @@ -287,6 +285,7 @@ __all__ = [ 'is_point_in_box', 'is_xcode_build', 'LanguageSubsystem', + 'lifecyclelog', 'lock_all_input', 'LoginAdapter', 'LoginInfo', @@ -356,6 +355,7 @@ __all__ = [ 'unlock_all_input', 'update_internal_logger_levels', 'user_agent_string', + 'user_ran_commands', 'utf8_all', 'Vec3', 'vec3validate', diff --git a/src/assets/ba_data/python/babase/_app.py b/src/assets/ba_data/python/babase/_app.py index 71320369..693946ea 100644 --- a/src/assets/ba_data/python/babase/_app.py +++ b/src/assets/ba_data/python/babase/_app.py @@ -24,6 +24,7 @@ from babase._appintent import AppIntentDefault, AppIntentExec from babase._stringedit import StringEditSubsystem from babase._devconsole import DevConsoleSubsystem from babase._appconfig import AppConfig +from babase._logging import lifecyclelog if TYPE_CHECKING: import asyncio @@ -871,7 +872,7 @@ class App: def _apply_app_config(self) -> None: assert _babase.in_logic_thread() - _babase.lifecyclelog('apply-app-config') + lifecyclelog.info('apply-app-config') # If multiple apply calls have been made, only actually apply # once. @@ -903,7 +904,7 @@ class App: if self._native_shutdown_complete_called: if self.state is not self.State.SHUTDOWN_COMPLETE: self.state = self.State.SHUTDOWN_COMPLETE - _babase.lifecyclelog(f'app-state is now {self.state.name}') + lifecyclelog.info('app-state is now %s', self.state.name) self._on_shutdown_complete() # Shutdown trumps all. Though we can't start shutting down until @@ -913,7 +914,7 @@ class App: # Entering shutdown state: if self.state is not self.State.SHUTTING_DOWN: self.state = self.State.SHUTTING_DOWN - _babase.lifecyclelog(f'app-state is now {self.state.name}') + lifecyclelog.info('app-state is now %s', self.state.name) self._on_shutting_down() elif self._native_suspended: @@ -930,7 +931,7 @@ class App: if self._initial_sign_in_completed and self._meta_scan_completed: if self.state != self.State.RUNNING: self.state = self.State.RUNNING - _babase.lifecyclelog(f'app-state is now {self.state.name}') + lifecyclelog.info('app-state is now %s', self.state.name) if not self._called_on_running: self._called_on_running = True self._on_running() @@ -939,7 +940,7 @@ class App: elif self._init_completed: if self.state is not self.State.LOADING: self.state = self.State.LOADING - _babase.lifecyclelog(f'app-state is now {self.state.name}') + lifecyclelog.info('app-state is now %s', self.state.name) if not self._called_on_loading: self._called_on_loading = True self._on_loading() @@ -948,7 +949,7 @@ class App: elif self._native_bootstrapping_completed: if self.state is not self.State.INITING: self.state = self.State.INITING - _babase.lifecyclelog(f'app-state is now {self.state.name}') + lifecyclelog.info('app-state is now %s', self.state.name) if not self._called_on_initing: self._called_on_initing = True self._on_initing() @@ -957,7 +958,7 @@ class App: elif self._native_start_called: if self.state is not self.State.NATIVE_BOOTSTRAPPING: self.state = self.State.NATIVE_BOOTSTRAPPING - _babase.lifecyclelog(f'app-state is now {self.state.name}') + lifecyclelog.info('app-state is now %s', self.state.name) else: # Only logical possibility left is NOT_STARTED, in which # case we should not be getting called. @@ -1068,10 +1069,10 @@ class App: # Spin and wait for anything blocking shutdown to complete. starttime = _babase.apptime() - _babase.lifecyclelog('shutdown-suppress-wait begin') + lifecyclelog.info('shutdown-suppress-wait begin') while _babase.shutdown_suppress_count() > 0: await asyncio.sleep(0.001) - _babase.lifecyclelog('shutdown-suppress-wait end') + lifecyclelog.info('shutdown-suppress-wait end') duration = _babase.apptime() - starttime if duration > 1.0: logging.warning( @@ -1084,7 +1085,7 @@ class App: import asyncio # Kick off a short fade and give it time to complete. - _babase.lifecyclelog('fade-and-shutdown-graphics begin') + lifecyclelog.info('fade-and-shutdown-graphics begin') _babase.fade_screen(False, time=0.15) await asyncio.sleep(0.15) @@ -1093,19 +1094,19 @@ class App: _babase.graphics_shutdown_begin() while not _babase.graphics_shutdown_is_complete(): await asyncio.sleep(0.01) - _babase.lifecyclelog('fade-and-shutdown-graphics end') + lifecyclelog.info('fade-and-shutdown-graphics end') async def _fade_and_shutdown_audio(self) -> None: import asyncio # Tell the audio system to go down and give it a bit of # time to do so gracefully. - _babase.lifecyclelog('fade-and-shutdown-audio begin') + lifecyclelog.info('fade-and-shutdown-audio begin') _babase.audio_shutdown_begin() await asyncio.sleep(0.15) while not _babase.audio_shutdown_is_complete(): await asyncio.sleep(0.01) - _babase.lifecyclelog('fade-and-shutdown-audio end') + lifecyclelog.info('fade-and-shutdown-audio end') def _threadpool_no_wait_done(self, fut: Future) -> None: try: diff --git a/src/assets/ba_data/python/babase/_logging.py b/src/assets/ba_data/python/babase/_logging.py new file mode 100644 index 00000000..946b7cbf --- /dev/null +++ b/src/assets/ba_data/python/babase/_logging.py @@ -0,0 +1,11 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Logging functionality.""" + +from __future__ import annotations + +import logging + +# Our standard set of loggers. +balog = logging.getLogger('ba') +lifecyclelog = logging.getLogger('ba.lifecycle') diff --git a/src/assets/ba_data/python/baclassic/_appmode.py b/src/assets/ba_data/python/baclassic/_appmode.py index c45c2221..9a6bc780 100644 --- a/src/assets/ba_data/python/baclassic/_appmode.py +++ b/src/assets/ba_data/python/baclassic/_appmode.py @@ -3,6 +3,7 @@ """Contains ClassicAppMode.""" from __future__ import annotations +import os import logging from functools import partial from typing import TYPE_CHECKING, override @@ -157,8 +158,8 @@ class ClassicAppMode(AppMode): """Update subscriptions/etc. for a new primary account state.""" assert in_logic_thread() - # Test subscription. - if bool(False): + # For testing subscription functionality. + if os.environ.get('BA_SUBSCRIPTION_TEST') == '1': assert app.plus is not None if account is None: self._test_sub = None diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index a7b287b6..bfb4a2d9 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -53,7 +53,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 22105 +TARGET_BALLISTICA_BUILD = 22106 TARGET_BALLISTICA_VERSION = '1.7.37' @@ -216,7 +216,7 @@ def configure( # (including cached history) to the os-specific output location. # This means anything printed or logged at this point forward should # be visible on all platforms. - log_handler = _setup_logging(launch_time) if setup_logging else None + log_handler = _create_log_handler(launch_time) if setup_logging else None # Load the raw app-config dict. app_config = _read_app_config(os.path.join(config_dir, 'config.json')) @@ -311,7 +311,7 @@ def _calc_data_dir(data_dir: str | None) -> str: return data_dir -def _setup_logging(launch_time: float) -> LogHandler: +def _create_log_handler(launch_time: float) -> LogHandler: from efro.logging import setup_logging, LogLevel log_handler = setup_logging( @@ -336,7 +336,8 @@ def _set_log_levels(app_config: dict) -> None: get_base_logger_control_config_client().apply() return - # Make sure data is expected types/values. + # Make sure data is expected types/values since this is user + # editable. valid_levels = { logging.NOTSET, logging.DEBUG, diff --git a/src/assets/ba_data/python/baplus/_cloud.py b/src/assets/ba_data/python/baplus/_cloud.py index a3a83aff..9e77a1ba 100644 --- a/src/assets/ba_data/python/baplus/_cloud.py +++ b/src/assets/ba_data/python/baplus/_cloud.py @@ -5,7 +5,6 @@ from __future__ import annotations import logging -from functools import partial from typing import TYPE_CHECKING, overload import babase @@ -179,35 +178,6 @@ class CloudSubsystem(babase.AppSubsystem): self, updatecall: Callable[[int | None], None] ) -> babase.CloudSubscription: """Subscribe to some data.""" - from bacommon.cloud import TestCloudSubscriptionRequest - - assert babase.in_logic_thread() - - return self._subscribe( - TestCloudSubscriptionRequest(), - partial(self._on_sub_value_test, updatecall), - ) - - @staticmethod - def _on_sub_value_test( - cb: Callable[[int | None], None], - invalue: bacommon.cloud.CloudSubscriptionValue, - ) -> None: - from bacommon.cloud import TestCloudSubscriptionValue - - assert babase.in_logic_thread() - - # Make sure we got the type we expected for this sub and pass it - # to the user callback. - assert isinstance(invalue, TestCloudSubscriptionValue) - cb(invalue.value) - - def _subscribe( - self, - request: bacommon.cloud.CloudSubscriptionRequest, - updatecall: Callable[[Any], None], - ) -> babase.CloudSubscription: - """Subscribe to some cloud data.""" raise NotImplementedError( 'Cloud functionality is not present in this build.' ) diff --git a/src/assets/ba_data/python/bauiv1lib/account/settings.py b/src/assets/ba_data/python/bauiv1lib/account/settings.py index fcdc49a0..92f18102 100644 --- a/src/assets/ba_data/python/bauiv1lib/account/settings.py +++ b/src/assets/ba_data/python/bauiv1lib/account/settings.py @@ -14,6 +14,7 @@ from bacommon.login import LoginType import bacommon.cloud import bauiv1 as bui +from bauiv1lib.connectivity import wait_for_connectivity # These days we're directing people to the web based account settings # for V2 account linking and trying to get them to disconnect remaining @@ -1180,19 +1181,17 @@ class AccountSettingsWindow(bui.MainWindow): self._do_manage_account_press(WebLocation.ACCOUNT_DELETE_SECTION) def _do_manage_account_press(self, weblocation: WebLocation) -> None: + # If we're still waiting for our master-server connection, + # keep the user informed of this instead of rushing in and + # failing immediately. + wait_for_connectivity( + on_connected=lambda: self._do_manage_account(weblocation) + ) + + def _do_manage_account(self, weblocation: WebLocation) -> None: plus = bui.app.plus assert plus is not None - # Preemptively fail if it looks like we won't be able to talk to - # the server anyway. - if not plus.cloud.connected: - bui.screenmessage( - bui.Lstr(resource='internal.unavailableNoConnectionText'), - color=(1, 0, 0), - ) - bui.getsound('error').play() - return - bui.screenmessage(bui.Lstr(resource='oneMomentText')) # We expect to have a v2 account signed in if we get here. @@ -1427,8 +1426,6 @@ class AccountSettingsWindow(bui.MainWindow): bui.apptimer(0.1, bui.WeakCall(self._update)) def _sign_in_press(self, login_type: str | LoginType) -> None: - from bauiv1lib.connectivity import wait_for_connectivity - # If we're still waiting for our master-server connection, # keep the user informed of this instead of rushing in and # failing immediately. @@ -1522,9 +1519,6 @@ class AccountSettingsWindow(bui.MainWindow): bui.apptimer(0.1, bui.WeakCall(self._update)) def _v2_proxy_sign_in_press(self) -> None: - # pylint: disable=cyclic-import - from bauiv1lib.connectivity import wait_for_connectivity - # If we're still waiting for our master-server connection, keep # the user informed of this instead of rushing in and failing # immediately. diff --git a/src/ballistica/base/base.cc b/src/ballistica/base/base.cc index 13106b94..7fa660e5 100644 --- a/src/ballistica/base/base.cc +++ b/src/ballistica/base/base.cc @@ -89,7 +89,7 @@ void BaseFeatureSet::OnModuleExec(PyObject* module) { assert(g_core == nullptr); g_core = core::CoreFeatureSet::Import(); - g_core->LifecycleLog("_babase exec begin"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "_babase exec begin"); // This locks in a baenv configuration. g_core->ApplyBaEnvConfig(); @@ -133,7 +133,7 @@ void BaseFeatureSet::OnModuleExec(PyObject* module) { assert(!g_base->base_native_import_completed_); g_base->base_native_import_completed_ = true; - g_core->LifecycleLog("_babase exec end"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "_babase exec end"); } void BaseFeatureSet::OnReachedEndOfBaBaseImport() { @@ -206,7 +206,8 @@ void BaseFeatureSet::StartApp() { called_start_app_ = true; assert(!app_started_); // Shouldn't be possible. - g_core->LifecycleLog("start-app begin (main thread)"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, + "start-app begin (main thread)"); LogVersionInfo_(); @@ -246,7 +247,8 @@ void BaseFeatureSet::StartApp() { python->objs().Get(BasePython::ObjID::kAppPushApplyAppConfigCall).Call(); } - g_core->LifecycleLog("start-app end (main thread)"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, + "start-app end (main thread)"); // Make some noise if this takes more than a few seconds. If we pass 5 // seconds or so we start to trigger App-Not-Responding reports which @@ -410,7 +412,8 @@ void BaseFeatureSet::OnAppShutdownComplete() { assert(g_base); // Flag our own event loop to exit (or ask the OS to if they're managing). - g_core->LifecycleLog("app exiting (main thread)"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, + "app exiting (main thread)"); if (app_adapter->ManagesMainThreadEventLoop()) { app_adapter->DoExitMainThreadEventLoop(); } else { diff --git a/src/ballistica/base/logic/logic.cc b/src/ballistica/base/logic/logic.cc index 3214bd0d..4c4a89de 100644 --- a/src/ballistica/base/logic/logic.cc +++ b/src/ballistica/base/logic/logic.cc @@ -37,7 +37,8 @@ void Logic::OnMainThreadStartApp() { void Logic::OnAppStart() { assert(g_base->InLogicThread()); - g_core->LifecycleLog("on-app-start begin (logic thread)"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, + "on-app-start begin (logic thread)"); // Our thread should not be holding the GIL here at the start (and // probably will not have any Python state at all). So here we set both @@ -73,7 +74,8 @@ void Logic::OnAppStart() { } g_base->python->OnAppStart(); - g_core->LifecycleLog("on-app-start end (logic thread)"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, + "on-app-start end (logic thread)"); } void Logic::OnGraphicsReady() { @@ -118,7 +120,8 @@ void Logic::CompleteAppBootstrapping_() { assert(!app_bootstrapping_complete_); app_bootstrapping_complete_ = true; - g_core->LifecycleLog("app native bootstrapping complete"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, + "app native bootstrapping complete"); // Let the assets system know it can start loading stuff now that // we have a screen and thus know texture formats/etc. diff --git a/src/ballistica/base/python/methods/python_methods_base_1.cc b/src/ballistica/base/python/methods/python_methods_base_1.cc index 71e5c0eb..e4ac7c02 100644 --- a/src/ballistica/base/python/methods/python_methods_base_1.cc +++ b/src/ballistica/base/python/methods/python_methods_base_1.cc @@ -855,31 +855,31 @@ static PyMethodDef PyEmitLogDef = { // ------------------------------ lifecyclelog --------------------------------- -static auto PyLifecycleLog(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - static const char* kwlist[] = {"message", nullptr}; - const char* message; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", - const_cast(kwlist), &message)) { - return nullptr; - } +// static auto PyLifecycleLog(PyObject* self, PyObject* args, PyObject* keywds) +// -> PyObject* { +// BA_PYTHON_TRY; +// static const char* kwlist[] = {"message", nullptr}; +// const char* message; +// if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", +// const_cast(kwlist), &message)) { +// return nullptr; +// } - g_core->LifecycleLog(message); +// g_core->LifecycleLog(message); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} +// Py_RETURN_NONE; +// BA_PYTHON_CATCH; +// } -static PyMethodDef PyLifecycleLogDef = { - "lifecyclelog", // name - (PyCFunction)PyLifecycleLog, // method - METH_VARARGS | METH_KEYWORDS, // flags +// static PyMethodDef PyLifecycleLogDef = { +// "lifecyclelog", // name +// (PyCFunction)PyLifecycleLog, // method +// METH_VARARGS | METH_KEYWORDS, // flags - "lifecyclelog(message: str) -> None\n" - "\n" - "(internal)", -}; +// "lifecyclelog(message: str) -> None\n" +// "\n" +// "(internal)", +// }; // ----------------------------- v1_cloud_log ---------------------------------- @@ -1722,7 +1722,7 @@ auto PythonMethodsBase1::GetMethods() -> std::vector { PyMacMusicAppPlayPlaylistDef, PyMacMusicAppGetPlaylistsDef, PyIsOSPlayingMusicDef, - PyLifecycleLogDef, + // PyLifecycleLogDef, PyExecArgDef, PyOnAppRunningDef, PyOnInitialAppModeSetDef, diff --git a/src/ballistica/classic/classic.cc b/src/ballistica/classic/classic.cc index 3b4b43c6..5ede6bff 100644 --- a/src/ballistica/classic/classic.cc +++ b/src/ballistica/classic/classic.cc @@ -30,7 +30,7 @@ void ClassicFeatureSet::OnModuleExec(PyObject* module) { assert(g_core == nullptr); g_core = core::CoreFeatureSet::Import(); - g_core->LifecycleLog("_baclassic exec begin"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "_baclassic exec begin"); // Create our feature-set's C++ front-end. assert(g_classic == nullptr); @@ -54,7 +54,7 @@ void ClassicFeatureSet::OnModuleExec(PyObject* module) { assert(g_scene_v1 == nullptr); g_scene_v1 = scene_v1::SceneV1FeatureSet::Import(); - g_core->LifecycleLog("_baclassic exec end"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "_baclassic exec end"); } ClassicFeatureSet::ClassicFeatureSet() diff --git a/src/ballistica/core/core.cc b/src/ballistica/core/core.cc index 111be9f1..63cf391e 100644 --- a/src/ballistica/core/core.cc +++ b/src/ballistica/core/core.cc @@ -78,15 +78,8 @@ void CoreFeatureSet::DoImport_(const CoreConfig& config) { g_core = new CoreFeatureSet(config); g_core->PostInit_(); - // Slightly hacky: have to report our begin time after the fact since core - // didn't exist before. Can at least add an offset to give an accurate - // time though. - auto seconds_since_actual_start = - static_cast(CorePlatform::GetCurrentMillisecs() - - start_millisecs) - / 1000.0; - g_core->LifecycleLog("core import begin", -seconds_since_actual_start); - g_core->LifecycleLog("core import end"); + // We can't report core import begin since core didn't exist at that point. + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "core import end"); } CoreFeatureSet::CoreFeatureSet(CoreConfig config) @@ -308,24 +301,24 @@ auto CoreFeatureSet::SoftImportBase() -> BaseSoftInterface* { return g_base_soft; } -void CoreFeatureSet::LifecycleLog(const char* msg, double offset_seconds) { - // Early out to avoid work if we won't show anyway. - if (!LogLevelEnabled(LogName::kBaLifecycle, LogLevel::kDebug)) { - return; - } +// void CoreFeatureSet::LifecycleLog(const char* msg, double offset_seconds) { +// // Early out to avoid work if we won't show anyway. +// if (!LogLevelEnabled(LogName::kBaLifecycle, LogLevel::kDebug)) { +// return; +// } - // We're now showing relative timestamps in more places so trying without - // adding that to the message... - if (explicit_bool(false)) { - // We include time-since-start as part of the message here. - char buffer[128]; - snprintf(buffer, sizeof(buffer), "%s @ %.3fs.", msg, - g_core->GetAppTimeSeconds() + offset_seconds); - Log(LogName::kBaLifecycle, LogLevel::kDebug, buffer); - } else { - Log(LogName::kBaLifecycle, LogLevel::kDebug, msg); - } -} +// // We're now showing relative timestamps in more places so trying without +// // adding that to the message... +// if (explicit_bool(false)) { +// // We include time-since-start as part of the message here. +// char buffer[128]; +// snprintf(buffer, sizeof(buffer), "%s @ %.3fs.", msg, +// g_core->GetAppTimeSeconds() + offset_seconds); +// Log(LogName::kBaLifecycle, LogLevel::kDebug, buffer); +// } else { +// Log(LogName::kBaLifecycle, LogLevel::kDebug, msg); +// } +// } void CoreFeatureSet::Log(LogName name, LogLevel level, char* msg) { // Avoid touching the Python layer if the log will get ignored there diff --git a/src/ballistica/core/core.h b/src/ballistica/core/core.h index 1766396c..7ba9e3f2 100644 --- a/src/ballistica/core/core.h +++ b/src/ballistica/core/core.h @@ -97,7 +97,7 @@ class CoreFeatureSet { } /// Log a boot-related message (only if core_config.lifecycle_log is true). - void LifecycleLog(const char* msg, double offset_seconds = 0.0); + // void LifecycleLog(const char* msg, double offset_seconds = 0.0); /// Base path of build src dir so we can attempt to remove it from any /// source file paths we print. diff --git a/src/ballistica/core/python/core_python.cc b/src/ballistica/core/python/core_python.cc index 2b111502..ba1bbd71 100644 --- a/src/ballistica/core/python/core_python.cc +++ b/src/ballistica/core/python/core_python.cc @@ -187,6 +187,8 @@ void CorePython::EnablePythonLoggingCalls() { assert(objs().Exists(ObjID::kLoggerRootLogCall)); assert(objs().Exists(ObjID::kLoggerBa)); assert(objs().Exists(ObjID::kLoggerBaLogCall)); + assert(objs().Exists(ObjID::kLoggerBaApp)); + assert(objs().Exists(ObjID::kLoggerBaAppLogCall)); assert(objs().Exists(ObjID::kLoggerBaAudio)); assert(objs().Exists(ObjID::kLoggerBaAudioLogCall)); assert(objs().Exists(ObjID::kLoggerBaDisplayTime)); @@ -260,6 +262,7 @@ void CorePython::UpdateInternalLoggerLevels(LogLevel* log_levels) { std::pair pairs[] = { {LogName::kRoot, ObjID::kLoggerRoot}, {LogName::kBa, ObjID::kLoggerBa}, + {LogName::kBaApp, ObjID::kLoggerBaApp}, {LogName::kBaAudio, ObjID::kLoggerBaAudio}, {LogName::kBaGraphics, ObjID::kLoggerBaGraphics}, {LogName::kBaDisplayTime, ObjID::kLoggerBaDisplayTime}, @@ -331,7 +334,8 @@ void CorePython::VerifyPythonEnvironment() { void CorePython::MonolithicModeBaEnvConfigure() { assert(g_buildconfig.monolithic_build()); assert(g_core); - g_core->LifecycleLog("baenv.configure() begin"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, + "baenv.configure() begin"); auto gil{Python::ScopedInterpreterLock()}; @@ -389,7 +393,7 @@ void CorePython::MonolithicModeBaEnvConfigure() { if (result.ValueIsString()) { FatalError("Environment setup failed:\n" + result.ValueAsString()); } - g_core->LifecycleLog("baenv.configure() end"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "baenv.configure() end"); } void CorePython::LoggingCall(LogName logname, LogLevel loglevel, @@ -434,6 +438,10 @@ void CorePython::LoggingCall(LogName logname, LogLevel loglevel, logcallobj = ObjID::kLoggerBaLogCall; handled = true; break; + case LogName::kBaApp: + logcallobj = ObjID::kLoggerBaAppLogCall; + handled = true; + break; case LogName::kBaAudio: logcallobj = ObjID::kLoggerBaAudioLogCall; handled = true; diff --git a/src/ballistica/core/python/core_python.h b/src/ballistica/core/python/core_python.h index 51fd6f2d..ff70f204 100644 --- a/src/ballistica/core/python/core_python.h +++ b/src/ballistica/core/python/core_python.h @@ -34,6 +34,8 @@ class CorePython { kLoggerRootLogCall, kLoggerBa, kLoggerBaLogCall, + kLoggerBaApp, + kLoggerBaAppLogCall, kLoggerBaAudio, kLoggerBaAudioLogCall, kLoggerBaDisplayTime, diff --git a/src/ballistica/scene_v1/scene_v1.cc b/src/ballistica/scene_v1/scene_v1.cc index 6c4c3fe9..d670d4d6 100644 --- a/src/ballistica/scene_v1/scene_v1.cc +++ b/src/ballistica/scene_v1/scene_v1.cc @@ -48,7 +48,7 @@ void SceneV1FeatureSet::OnModuleExec(PyObject* module) { assert(g_core == nullptr); g_core = core::CoreFeatureSet::Import(); - g_core->LifecycleLog("_bascenev1 exec begin"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "_bascenev1 exec begin"); // Create our feature-set's C++ front-end. assert(g_scene_v1 == nullptr); @@ -68,7 +68,7 @@ void SceneV1FeatureSet::OnModuleExec(PyObject* module) { assert(g_base == nullptr); g_base = base::BaseFeatureSet::Import(); - g_core->LifecycleLog("_bascenev1 exec end"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "_bascenev1 exec end"); } SceneV1FeatureSet::SceneV1FeatureSet() : python{new SceneV1Python()} { diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 7569c6c6..cdbead5b 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 22105; +const int kEngineBuildNumber = 22106; const char* kEngineVersion = "1.7.37"; const int kEngineApiVersion = 9; diff --git a/src/ballistica/shared/foundation/types.h b/src/ballistica/shared/foundation/types.h index 7d7a07aa..e68b60d1 100644 --- a/src/ballistica/shared/foundation/types.h +++ b/src/ballistica/shared/foundation/types.h @@ -287,6 +287,7 @@ enum class PyExcType : uint8_t { enum class LogName : uint8_t { kRoot, kBa, + kBaApp, kBaDisplayTime, kBaLifecycle, kBaAudio, diff --git a/src/ballistica/ui_v1/ui_v1.cc b/src/ballistica/ui_v1/ui_v1.cc index ed3bff89..5cda5ddf 100644 --- a/src/ballistica/ui_v1/ui_v1.cc +++ b/src/ballistica/ui_v1/ui_v1.cc @@ -32,7 +32,7 @@ void UIV1FeatureSet::OnModuleExec(PyObject* module) { // Various ballistica functionality will fail if this has not been done. g_core = core::CoreFeatureSet::Import(); - g_core->LifecycleLog("_bauiv1 exec begin"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "_bauiv1 exec begin"); // Create our feature-set's C++ front-end. assert(g_ui_v1 == nullptr); @@ -52,7 +52,7 @@ void UIV1FeatureSet::OnModuleExec(PyObject* module) { assert(g_base == nullptr); // Should be getting set once here. g_base = base::BaseFeatureSet::Import(); - g_core->LifecycleLog("_bauiv1 exec end"); + g_core->Log(LogName::kBaLifecycle, LogLevel::kInfo, "_bauiv1 exec end"); } auto UIV1FeatureSet::Import() -> UIV1FeatureSet* { diff --git a/src/meta/bacoremeta/pyembed/binding_core.py b/src/meta/bacoremeta/pyembed/binding_core.py index 8e5db577..1a6ebbeb 100644 --- a/src/meta/bacoremeta/pyembed/binding_core.py +++ b/src/meta/bacoremeta/pyembed/binding_core.py @@ -27,6 +27,8 @@ values = [ logging.getLogger('root').log, # kLoggerRootLogCall logging.getLogger('ba'), # kLoggerBa logging.getLogger('ba').log, # kLoggerBaLogCall + logging.getLogger('ba.app'), # kLoggerBaApp + logging.getLogger('ba.app').log, # kLoggerBaAppLogCall logging.getLogger('ba.audio'), # kLoggerBaAudio logging.getLogger('ba.audio').log, # kLoggerBaAudioLogCall logging.getLogger('ba.displaytime'), # kLoggerBaDisplayTime diff --git a/tools/bacommon/cloud.py b/tools/bacommon/cloud.py index 4975e16f..2c665721 100644 --- a/tools/bacommon/cloud.py +++ b/tools/bacommon/cloud.py @@ -325,12 +325,14 @@ class BSPrivatePartyResponse(Response): datacode: Annotated[str | None, IOAttrs('d')] +# MOVE THIS class CloudSubscriptionRequestTypeID(Enum): """Type ID for each of our subclasses.""" TEST = 'test' +# MOVE THIS class CloudSubscriptionRequest(IOMultiType[CloudSubscriptionRequestTypeID]): """Top level class for our multitype.""" @@ -360,6 +362,7 @@ class CloudSubscriptionRequest(IOMultiType[CloudSubscriptionRequestTypeID]): return out +# MOVE THIS @ioprepped @dataclass class TestCloudSubscriptionRequest(CloudSubscriptionRequest): @@ -371,14 +374,16 @@ class TestCloudSubscriptionRequest(CloudSubscriptionRequest): return CloudSubscriptionRequestTypeID.TEST +# MOVE THIS class CloudSubscriptionValueTypeID(Enum): """Type ID for each of our subclasses.""" TEST = 'test' +# MOVE THIS class CloudSubscriptionValue(IOMultiType[CloudSubscriptionValueTypeID]): - """Top level class for our multitype.""" + """Top level class for subscription values.""" @override @classmethod diff --git a/tools/bacommon/logging.py b/tools/bacommon/logging.py index 120b96ee..723c9fc5 100644 --- a/tools/bacommon/logging.py +++ b/tools/bacommon/logging.py @@ -20,8 +20,8 @@ def get_base_logger_control_config_client() -> LoggerControlConfig: """ # By default, go with WARNING on everything to keep things mostly - # clean but show INFO for ba.lifecycle to get basic app - # startup/shutdown messages. + # clean but show INFO for ba.app to get basic app startup messages + # and whatnot. return LoggerControlConfig( - levels={'root': logging.WARNING, 'ba.lifecycle': logging.INFO} + levels={'root': logging.WARNING, 'ba.app': logging.INFO} ) diff --git a/tools/efro/error.py b/tools/efro/error.py index fed4252c..3411573f 100644 --- a/tools/efro/error.py +++ b/tools/efro/error.py @@ -251,6 +251,11 @@ def is_asyncio_streams_communication_error(exc: BaseException) -> bool: if 'SSL: WRONG_VERSION_NUMBER' in excstr: return True + # Also getting this sometimes which sounds like corrupt SSL data + # or something. + if 'SSL: BAD_RECORD_TYPE' in excstr: + return True + # And seeing this very rarely; assuming its just data corruption? if 'SSL: DECRYPTION_FAILED_OR_BAD_RECORD_MAC' in excstr: return True diff --git a/tools/efro/util.py b/tools/efro/util.py index 3c8a7851..1ef63588 100644 --- a/tools/efro/util.py +++ b/tools/efro/util.py @@ -169,21 +169,26 @@ def data_size_str(bytecount: int, compact: bool = False) -> str: class DirtyBit: - """Manages whether a thing is dirty and regulates attempts to clean it. + """Manages whether a thing is dirty and regulates cleaning it. + + To use, simply set the 'dirty' value on this object to True when + some update is needed, and then check the 'should_update' value to + regulate when the actual update should occur. Set 'dirty' back to + False after a successful update. + + If 'use_lock' is True, an asyncio Lock will be created and + incorporated into update attempts to prevent simultaneous updates + (should_update will only return True when the lock is unlocked). + Note that It is up to the user to lock/unlock the lock during the + actual update attempt. + + If a value is passed for 'auto_dirty_seconds', the dirtybit will + flip itself back to dirty after being clean for the given amount of + time. - To use, simply set the 'dirty' value on this object to True when some - action is needed, and then check the 'should_update' value to regulate - when attempts to clean it should be made. Set 'dirty' back to False after - a successful update. - If 'use_lock' is True, an asyncio Lock will be created and incorporated - into update attempts to prevent simultaneous updates (should_update will - only return True when the lock is unlocked). Note that It is up to the user - to lock/unlock the lock during the actual update attempt. - If a value is passed for 'auto_dirty_seconds', the dirtybit will flip - itself back to dirty after being clean for the given amount of time. 'min_update_interval' can be used to enforce a minimum update - interval even when updates are successful (retry_interval only applies - when updates fail) + interval even when updates are successful (retry_interval only + applies when updates fail) """ def __init__(