Cleaning up python bootstrapping code

This commit is contained in:
Eric Froemling 2021-04-15 14:23:42 -07:00
parent ff1001e41e
commit 97c14e7e10
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
10 changed files with 203 additions and 206 deletions

View File

@ -3932,40 +3932,40 @@
"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_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/77/45/69456cef2c9fddd5bb6a3497972b",
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/87/6d/1bc0e1c667216e278e7c95050955",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f6/b1/713661602c7580e060a5b2f5391c",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/2c/526bd742d1a1763d500bbfdfd763",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/30/f1/57680bd744ac6825dc44641c7f3f",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/71/5a/738514f3af01ecf3c806239e22e6",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/20/26/2145ff72ccd4f408a27da6b42b82",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/e1/9dc07498dd96f73540290c884287",
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e5/99/22214c0b91bcc3298568c87b6487",
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/75/ae/0d37c72901fdfb64e8104aa1406f",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cb/24/c5bb95114f793bc857504446a59e",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/53/0e/6725c8e8fa2c25e431e10b40384d",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/06/5e/694a00eb244e4925a1c3f74b5f02",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/32/f1/3a137d806dff7845d7e2dc766452",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f2/c6/b97c5eeea5307d0c679a9d2fa869",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/76/80/08157eac8b97c0d68802f90120f9",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c8/88/996fd4b6e10df4afbd23263da36f",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/27/98/b2fff1ad82e5cbc25eac397e4ae6",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c1/69/62108258025dea6f8e7488e0e802",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3d/4d/b6cee501623ef5d78fb15bc87215",
"build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b8/55/25ff15308d89838699e158024f9c",
"build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/dd/84/13497d8139e3b6095a87940188af",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b5/de/6e368b0f405c9fbed0e9e6ab0e6a",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/86/f0/6296ed8275094c2c1c96bbe98b56",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d9/7c/f166ddf0d1720ccea1720a1c2965",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/75/b3/5cad6cf47697b6f03bea6369ef5b",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d5/3a/fa01e178b6da2879864b50252c98",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/48/4d/a3d1385420e5866559c210c584f1",
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6e/3e/1f7b71a7639703bb13d71fb36ae9",
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8e/c1/373ad978ad9807f64baf6215a230",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8a/d6/17652e3a94201b26b228d2fc53df",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7a/36/3267309a349385e52af77a2738a1",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b8/d1/0318bfa712c7e6ef0d46c9b25033",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/58/5f/1f0121bd900ad5345e9a27cd6198",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/be/53/9de41660d67305ac5669141e557c",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/27/d6/b5d5e1a56aaa00acf174dc609b59"
"build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/27/04/dcdd63a27fa11e8dc5bb02dc8209",
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ab/0d/18fc7018dd73403b6e6d8739808d",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/74/457bda7850348dbcdd235cfa9dcb",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/a3/26eaba91b4384e2838cadad11ff6",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/80/64406ad4b21b8c75c3cf7dba3c98",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/bc/d4/5efe586e439de930ccbba8869c06",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7c/65/b95d5b30731ed29e04cb10572fe5",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8e/7f/e179cf95dd54e437bfd22961afd7",
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/73/911011e52f90d326ddf9cea03c84",
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4b/21/08678761775f2207e2f62994f79b",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/0a/baa2efe432186b7b3c2c20883aed",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ff/95/6668eb64a8c30470c223f217baaf",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/64/34/675c88ad196cbebdb0c19b51af41",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/56/2d/e58c62aecbf09c9d68be9fb4ef39",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/2f/f3faa8cc336fddf54c55b9b35e7d",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c0/b7/26d1c7b5a21cae8dc6911d02c5db",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1d/5e/ef2468327ef8ec8a0023219e251c",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3b/2a/f7f7ba687d28f429e416472c0c85",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bc/a1/703f357d2248c8b5674fa8bc3b8a",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/82/c9/a5811e1a80394e227366778380c1",
"build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9f/e1/17ec8710e6f9354dec40b134d963",
"build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/02/90/d56f5d876b4d128f4c52a2c2ab01",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/25/0e/d813586a741bf4d15623899d5f74",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e2/dc/3164ed18198ff5021746a5e2e3a6",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0c/be/6c258d57bf30c94b3dc7a03281e1",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/bd/f9/3b68d1abda8ba917f7084a675009",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4e/26/0f15c8533717ffeeae0b388546c2",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fb/89/e6c72ccad50cc3c0a34c4764d72c",
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/79/38/7fed4d2f7f8e158c44939ca6f09f",
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/1b/cd/1643ee0514a1fc57071b673c283e",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a0/2d/413df7c810b283fa6d67b41e1fbe",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ff/e9/8eba3a5244b95e17887568fa3540",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f7/4e/e98d85cbc5eeb67d916493776e53",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a7/53/c9f849fc8985b5dbad0044b3e967",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/17/ea/1fd0bcc743cc452c898d04bf9da2",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7f/14/bfe45f3ce7a374810f5d91204c80"
}

View File

@ -2048,6 +2048,7 @@
<w>stickman</w>
<w>storable</w>
<w>storagename</w>
<w>storecmd</w>
<w>storedhash</w>
<w>storeitemui</w>
<w>storename</w>

View File

@ -895,6 +895,7 @@
<w>stephane</w>
<w>stepnum</w>
<w>stepsize</w>
<w>storecmd</w>
<w>strcasecmp</w>
<w>strchr</w>
<w>strcpy</w>

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2021-04-15 for Ballistica version 1.6.0 build 20338</em></h4>
<h4><em>last updated on 2021-04-15 for Ballistica version 1.6.0 build 20339</em></h4>
<p>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 <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr>

View File

@ -21,7 +21,7 @@
namespace ballistica {
// These are set automatically via script; don't change here.
const int kAppBuildNumber = 20339;
const int kAppBuildNumber = 20340;
const char* kAppVersion = "1.6.0";
// Our standalone globals.

View File

@ -947,7 +947,9 @@ void Python::Reset(bool do_init) {
+ std::string(ver));
}
StoreObj(ObjID::kEmptyTuple, PyTuple_New(0));
// Create a dict for execing our bootstrap code in so
// we don't pollute the __main__ namespace.
auto bootstrap_context{PythonRef(PyDict_New(), PythonRef::kSteal)};
// Get the app up and running.
// Run a few core bootstrappy things first:
@ -956,21 +958,17 @@ void Python::Reset(bool do_init) {
// - import and instantiate our app-state class
#include "generated/ballistica/bootstrap.inc"
int result = PyRun_SimpleString(bootstrap_code);
if (result != 0) {
PyObject* result =
PyRun_String(bootstrap_code, Py_file_input, bootstrap_context.get(),
bootstrap_context.get());
if (result == nullptr) {
PyErr_PrintEx(0);
// Throw a simple exception so we don't get a stack trace.
throw std::logic_error(
"Error in ba Python bootstrapping. See log for details.");
}
PyObject* appstate = PythonCommand("app_state", "<AppStateFetch>")
.RunReturnObj(false, nullptr);
if (appstate == nullptr) {
throw Exception("Unable to get value: '" + std::string("app_state")
+ "'.");
}
StoreObj(ObjID::kApp, appstate);
Py_DECREF(result);
// Import and grab all the Python stuff we use.
#include "generated/ballistica/binding.inc"

View File

@ -4,25 +4,36 @@
# Run make update to update the project after editing this..
# pylint: disable=missing-module-docstring, missing-function-docstring
# pylint: disable=line-too-long
def get_binding_values() -> object:
from ba import _hooks
import _ba
import json
import copy
import ba
from ba import _language
from ba import _music
from ba import _input
from ba import _apputils
from ba import _account
from ba import _dependency
from ba import _enums
from ba import _player
# FIXME: There should be no bastd in here;
# should pull in bases from ba which get overridden by bastd (or other).
from bastd.ui.onscreenkeyboard import OnScreenKeyboardWindow
from bastd.ui import party
from __future__ import annotations
import json
import copy
from typing import TYPE_CHECKING
import ba
from ba import _language
from ba import _music
from ba import _input
from ba import _apputils
from ba import _dependency
from ba import _enums
from ba import _player
from ba import _hooks
import _ba
# FIXME: There should be no bastd in here;
# should pull in bases from ba which get overridden by bastd (or other).
from bastd.ui.onscreenkeyboard import OnScreenKeyboardWindow
from bastd.ui import party
if TYPE_CHECKING:
from typing import Tuple, Any
def get_binding_values() -> Tuple[Any, ...]:
return (
ba.app, # kApp
tuple(), # kEmptyTuple
_ba.client_info_query_response, # kClientInfoQueryResponseCall
_hooks.reset_to_main_menu, # kResetToMainMenuCall
_hooks.set_config_fullscreen_on, # kSetConfigFullscreenOnCall

View File

@ -3,145 +3,136 @@
from __future__ import annotations
import sys
import signal
import threading
from typing import TYPE_CHECKING
import _ba
if TYPE_CHECKING:
from typing import Any, TextIO, Callable, List
def _ballistica_bootstrap() -> object:
import sys
import signal
import _ba
import threading
class _BAConsoleRedirect:
class _BAConsoleRedirect:
def __init__(self, original: TextIO, call: Callable[[str], None]) -> None:
self._lock = threading.Lock()
self._linebits: List[str] = []
self._original = original
self._call = call
self._pending_ship = False
def __init__(self, original: TextIO, call: Callable[[str],
None]) -> None:
self._lock = threading.Lock()
self._linebits: List[str] = []
self._original = original
self._call = call
self._pending_ship = False
def write(self, sval: Any) -> None:
"""Override standard stdout write."""
def write(self, sval: Any) -> None:
"""Override standard stdout write."""
self._call(sval)
self._call(sval)
# Now do logging:
# Add it to our accumulated line.
# If the message ends in a newline, we can ship it
# immediately as a log entry. Otherwise, schedule a ship
# next cycle (if it hasn't yet at that point) so that we
# can accumulate subsequent prints.
# (so stuff like print('foo', 123, 'bar') will ship as one entry)
with self._lock:
self._linebits.append(sval)
if sval.endswith('\n'):
self._shiplog()
else:
_ba.pushcall(self._shiplog,
from_other_thread=True,
suppress_other_thread_warning=True)
# Now do logging:
# Add it to our accumulated line.
# If the message ends in a newline, we can ship it
# immediately as a log entry. Otherwise, schedule a ship
# next cycle (if it hasn't yet at that point) so that we
# can accumulate subsequent prints.
# (so stuff like print('foo', 123, 'bar') will ship as one entry)
with self._lock:
self._linebits.append(sval)
if sval.endswith('\n'):
self._shiplog()
else:
_ba.pushcall(self._shiplog,
from_other_thread=True,
suppress_other_thread_warning=True)
def _shiplog(self) -> None:
with self._lock:
line = ''.join(self._linebits)
if not line:
return
self._linebits = []
def _shiplog(self) -> None:
with self._lock:
line = ''.join(self._linebits)
if not line:
return
self._linebits = []
# Log messages aren't expected to have trailing newlines.
if line.endswith('\n'):
line = line[:-1]
_ba.log(line, to_stdout=False)
# Log messages aren't expected to have trailing newlines.
if line.endswith('\n'):
line = line[:-1]
_ba.log(line, to_stdout=False)
def flush(self) -> None:
"""Flush the file."""
self._original.flush()
def flush(self) -> None:
"""Flush the file."""
self._original.flush()
def isatty(self) -> bool:
"""Are we a terminal?"""
return self._original.isatty()
sys.stdout = _BAConsoleRedirect( # type: ignore
sys.stdout, _ba.print_stdout)
sys.stderr = _BAConsoleRedirect( # type: ignore
sys.stderr, _ba.print_stderr)
# Let's lookup mods first (so users can do whatever they want).
# and then our bundled scripts last (don't want to encourage dists
# overriding proper python functionality)
sys.path.insert(0, _ba.env()['python_directory_user'])
sys.path.append(_ba.env()['python_directory_app'])
sys.path.append(_ba.env()['python_directory_app_site'])
# Tell Python to not handle SIGINT itself (it normally generates
# KeyboardInterrupts which make a mess; we want to do a simple
# clean exit). We capture interrupts per-platform in the C++ layer.
# I tried creating a handler in Python but it seemed to often have
# a delay of up to a second before getting called. (not a huge deal
# but I'm picky).
signal.signal(signal.SIGINT, signal.SIG_DFL) # Do default handling.
# ..though it turns out we need to set up our C signal handling AFTER
# we've told Python to disable its own; otherwise (on Mac at least) it
# wipes out our existing C handler.
_ba.setup_sigint()
# Sanity check: we should always be run in UTF-8 mode.
if sys.flags.utf8_mode != 1:
print('ERROR: Python\'s UTF-8 mode is not set.'
' This will likely result in errors.')
# FIXME: I think we should init Python in the main thread, which should
# also avoid these issues. (and also might help us play better with
# Python debuggers?)
# Gloriously hacky workaround here:
# Our 'main' Python thread is the game thread (not the app's main
# thread) which means it has a small stack compared to the main
# thread (at least on apple). Sadly it turns out this causes the
# debug build of Python to blow its stack immediately when doing
# some big imports.
# Normally we'd just give the game thread the same stack size as
# the main thread and that'd be the end of it. However
# we're using std::threads which it turns out have no way to set
# the stack size (as of fall '19). Grumble.
#
# However python threads *can* take custom stack sizes.
# (and it appears they might use the main thread's by default?..)
# ...so as a workaround in the debug version, we can run problematic
# heavy imports here in another thread and all is well.
# If we ever see stack overflows in our release build we'll have
# to take more drastic measures like switching from std::threads
# to pthreads.
if _ba.env()['debug_build']:
def _thread_func() -> None:
# pylint: disable=unused-import
import json
import urllib.request
testthread = threading.Thread(target=_thread_func)
testthread.start()
testthread.join()
# Now spin up our App instance, store it on both _ba and ba,
# and return it to the C++ layer.
# noinspection PyProtectedMember
from ba._app import App
import ba
app = App()
_ba.app = app
ba.app = app
return app
def isatty(self) -> bool:
"""Are we a terminal?"""
return self._original.isatty()
app_state = _ballistica_bootstrap()
sys.stdout = _BAConsoleRedirect(sys.stdout, _ba.print_stdout) # type: ignore
sys.stderr = _BAConsoleRedirect(sys.stderr, _ba.print_stderr) # type: ignore
# This code runs in the main namespace, so clean up after ourself.
del _ballistica_bootstrap, TYPE_CHECKING
# Let's lookup mods first (so users can do whatever they want).
# and then our bundled scripts last (don't want to encourage dists
# overriding proper python functionality)
sys.path.insert(0, _ba.env()['python_directory_user'])
sys.path.append(_ba.env()['python_directory_app'])
sys.path.append(_ba.env()['python_directory_app_site'])
# Tell Python to not handle SIGINT itself (it normally generates
# KeyboardInterrupts which make a mess; we want to do a simple
# clean exit). We capture interrupts per-platform in the C++ layer.
# I tried creating a handler in Python but it seemed to often have
# a delay of up to a second before getting called. (not a huge deal
# but I'm picky).
signal.signal(signal.SIGINT, signal.SIG_DFL) # Do default handling.
# ..though it turns out we need to set up our C signal handling AFTER
# we've told Python to disable its own; otherwise (on Mac at least) it
# wipes out our existing C handler.
_ba.setup_sigint()
# Sanity check: we should always be run in UTF-8 mode.
if sys.flags.utf8_mode != 1:
print('ERROR: Python\'s UTF-8 mode is not set.'
' This will likely result in errors.')
# FIXME: I think we should init Python in the main thread, which should
# also avoid these issues. (and also might help us play better with
# Python debuggers?)
# Gloriously hacky workaround here:
# Our 'main' Python thread is the game thread (not the app's main
# thread) which means it has a small stack compared to the main
# thread (at least on apple). Sadly it turns out this causes the
# debug build of Python to blow its stack immediately when doing
# some big imports.
# Normally we'd just give the game thread the same stack size as
# the main thread and that'd be the end of it. However
# we're using std::threads which it turns out have no way to set
# the stack size (as of fall '19). Grumble.
#
# However python threads *can* take custom stack sizes.
# (and it appears they might use the main thread's by default?..)
# ...so as a workaround in the debug version, we can run problematic
# heavy imports here in another thread and all is well.
# If we ever see stack overflows in our release build we'll have
# to take more drastic measures like switching from std::threads
# to pthreads.
if _ba.env()['debug_build']:
def _thread_func() -> None:
# pylint: disable=unused-import
import json
import urllib.request
testthread = threading.Thread(target=_thread_func)
testthread.start()
testthread.join()
del testthread
# Now spin up our App instance, store it on both _ba and ba,
# and return it to the C++ layer.
# noinspection PyProtectedMember
# pylint: disable=wrong-import-position
from ba._app import App
import ba
_ba.app = ba.app = App()

View File

@ -96,7 +96,7 @@ def _lazybuild_check_paths(inpaths: List[str], category: SourceCategory,
def _testpath(path: str) -> bool:
# Now see this path is newer than our target..
if mtime is None or os.path.getmtime(path) >= mtime:
print(f'{Clr.SMAG}Build of {tnamepretty} triggered by'
print(f'{Clr.SMAG}Build of {tnamepretty} triggered by change in'
f" '{path}'{Clr.RST}")
return True
return False

View File

@ -69,8 +69,9 @@ def gen_binding_code(projroot: str, in_path: str, out_path: str) -> None:
# Our C++ code first execs our input as a string.
ccode = ('{const char* bindcode = ' + repr(pycode).replace("'", '"') + ';')
ccode += ('\nint result = PyRun_SimpleString(bindcode);\n'
'if (result != 0) {\n'
ccode += ('\nPyObject* result = PyRun_String(bindcode, Py_file_input,'
' bootstrap_context.get(), bootstrap_context.get());\n'
'if (result == nullptr) {\n'
' PyErr_PrintEx(0);\n'
' // Use a standard error to avoid a useless stack trace.\n'
' throw std::logic_error("Error fetching required Python'
@ -80,7 +81,7 @@ def gen_binding_code(projroot: str, in_path: str, out_path: str) -> None:
# Then it grabs the function that was defined and runs it.
ccode += ('PyObject* bindvals = PythonCommand("get_binding_values()",'
' "<get_binding_values>")'
'.RunReturnObj(true, nullptr);\n'
'.RunReturnObj(true, bootstrap_context.get());\n'
'if (bindvals == nullptr) {\n'
' // Use a standard error to avoid a useless stack trace.\n'
' throw std::logic_error("Error binding required Python'
@ -89,18 +90,12 @@ def gen_binding_code(projroot: str, in_path: str, out_path: str) -> None:
# Then it pulls the individual values out of the returned tuple.
for i, line in enumerate(lines):
ccode += ('StoreObjCallable(ObjID::' + line[1] +
', PyTuple_GET_ITEM(bindvals, ' + str(i) + '), true);\n')
storecmd = ('StoreObjCallable' if line[1].endswith('Class')
or line[1].endswith('Call') else 'StoreObj')
ccode += (f'{storecmd}(ObjID::{line[1]},'
f' PyTuple_GET_ITEM(bindvals, {i}), true);\n')
# Lastly it cleans up after itself.
ccode += ('result = PyRun_SimpleString("del get_binding_values");\n'
'if (result != 0) {\n'
' PyErr_PrintEx(0);\n'
' // Use a standard error to avoid a useless stack trace.\n'
' throw std::logic_error("Error cleaning up after Python'
' binding.");\n'
'}\n'
'}\n')
ccode += 'Py_DECREF(bindvals);\n}\n'
pretty_path = os.path.abspath(out_path)
if pretty_path.startswith(projroot + '/'):
pretty_path = pretty_path[len(projroot) + 1:]