def test_missing_resource(clean_assets): a = Asset('ppb/dont.touch.this') engine = GameEngine( AssetTestScene, basic_systems=[AssetLoadingSystem, Failer], fail=lambda e: False, message=None, run_time=1, ) with engine: engine.start() with pytest.raises(FileNotFoundError): assert a.load()
def test_missing_package(clean_assets): a = Asset('does/not/exist') engine = GameEngine( AssetTestScene, basic_systems=[AssetLoadingSystem, Failer], fail=lambda e: False, message=None, run_time=1, ) with engine: engine.start() with pytest.raises(FileNotFoundError): assert a.load()
def __init__(self, name, *, size, index=None): """ :param name: the filename to load :param size: the size in points :param index: the index of the font in a multi-font file (rare) """ # We do it this way so that the raw data can be cached between multiple # invocations, even though we have to reparse it every time. self._data = Asset(name) self.size = size self.index = index self._start(self._data)
def test_instance_condense(): class SubAsset(Asset): pass a1 = Asset('ppb/engine.py') a2 = Asset('ppb/engine.py') a3 = Asset('ppb/scenes.py') s1 = SubAsset('ppb/engine.py') assert a1 is a2 assert a1 is not a3 assert a1 is not s1
def test_loading(clean_assets): a = Asset('ppb/engine.py') engine = GameEngine( AssetTestScene, basic_systems=[AssetLoadingSystem, Failer], fail=lambda e: False, message=None, run_time=1, ) with engine: engine.start() ats = engine.current_scene engine.main_loop() assert a.load() print(vars(ats)) assert ats.ale.asset is a assert ats.ale.total_loaded == 1 assert ats.ale.total_queued == 0
class Font(ChainingMixin, FreeingMixin, AbstractAsset): """ A TrueType/OpenType Font """ def __init__(self, name, *, size, index=None): """ :param name: the filename to load :param size: the size in points :param index: the index of the font in a multi-font file (rare) """ # We do it this way so that the raw data can be cached between multiple # invocations, even though we have to reparse it every time. self._data = Asset(name) self.size = size self.index = index self._start(self._data) def _background(self): self._file = rw_from_object(io.BytesIO(self._data.load())) # We have to keep the file around because freetype doesn't load # everything at once, resulting in segfaults. with _freetype_lock: # Doing this so that we "refcount" the FT_Library internal to SDL_ttf # (TTF_CloseFont is often called after system cleanup) ttf_call(TTF_Init, _check_error=lambda rv: rv == -1) if self.index is None: return ttf_call( TTF_OpenFontRW, self._file, False, self.size, _check_error=lambda rv: not rv ) else: return ttf_call( TTF_OpenFontIndexRW, self._file, False, self.size, self.index, _check_error=lambda rv: not rv ) def free(self, data, _TTF_CloseFont=TTF_CloseFont, _lock=_freetype_lock, _TTF_Quit=TTF_Quit): # ^^^ is a way to keep required functions during interpreter cleanup with _lock: _TTF_CloseFont(data) # Can't fail _TTF_Quit() def __repr__(self): return f"<{type(self).__name__} name={self.name!r} size={self.size!r}{' loaded' if self.is_loaded() else ''} at {id(self):x}>" @property def name(self): return self._data.name def resize(self, size): """ Returns a new copy of this font in a different size """ return type(self)(self._data.name, size=size, index=self._index) @property def _is_fixed_width(self): return bool(TTF_FontFaceIsFixedWidth(self.load())) @property def _family_name(self): return TTF_FontFaceFamilyName(self.load()) @property def _style_name(self): return TTF_FontFaceStyleName(self.load())