pyglet at 2.0!!!!!!!!!!

This commit is contained in:
shenjack 2022-11-01 18:34:13 +08:00
parent 7343edc8a8
commit d67b35e40a
25 changed files with 163 additions and 174 deletions

View File

@ -44,10 +44,10 @@ import sys
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
#: The release version #: The release version
version = '2.0.b2' version = '2.0.0'
__version__ = version __version__ = version
MIN_PYTHON_VERSION = 3, 7 MIN_PYTHON_VERSION = 3, 8
MIN_PYTHON_VERSION_STR = '.'.join([str(v) for v in MIN_PYTHON_VERSION]) MIN_PYTHON_VERSION_STR = '.'.join([str(v) for v in MIN_PYTHON_VERSION])
if sys.version_info < MIN_PYTHON_VERSION: if sys.version_info < MIN_PYTHON_VERSION:
@ -198,7 +198,7 @@ _option_types = {
for key in options: for key in options:
"""Read defaults for options from environment""" """Read defaults for options from environment"""
assert key in _option_types, f"Option '{key}' must have a type set in _option_types." assert key in _option_types, f"Option '{key}' must have a type set in _option_types."
env = f'PYGLET_{key.upper()}' env = 'PYGLET_%s' % key.upper()
try: try:
value = os.environ[env] value = os.environ[env]
if _option_types[key] is tuple: if _option_types[key] is tuple:
@ -265,21 +265,21 @@ def _trace_frame(thread, frame, indent):
filename = os.path.join('...', filename) filename = os.path.join('...', filename)
_trace_filename_abbreviations[path] = filename _trace_filename_abbreviations[path] = filename
location = f'({filename}:{line})' location = '(%s:%d)' % (filename, line)
if indent: if indent:
name = f'Called from {name}' name = 'Called from %s' % name
print(f'[{thread}] {indent}{name} {location}') print('[%d] %s%s %s' % (thread, indent, name, location))
if _trace_args: if _trace_args:
if is_ctypes: if is_ctypes:
args = [_trace_repr(arg) for arg in frame.f_locals['args']] args = [_trace_repr(arg) for arg in frame.f_locals['args']]
print(f' {indent}args=({", ".join(args)})') print(' %sargs=(%s)' % (indent, ', '.join(args)))
else: else:
for argname in code.co_varnames[:code.co_argcount]: for argname in code.co_varnames[:code.co_argcount]:
try: try:
argvalue = _trace_repr(frame.f_locals[argname]) argvalue = _trace_repr(frame.f_locals[argname])
print(f' {indent}{argname}={argvalue}') print(' %s%s=%s' % (indent, argname, argvalue))
except: except:
pass pass
@ -335,7 +335,7 @@ class _ModuleProxy:
if self._module is not None: if self._module is not None:
raise raise
import_name = f'pyglet.{self._module_name}' import_name = 'pyglet.%s' % self._module_name
__import__(import_name) __import__(import_name)
module = sys.modules[import_name] module = sys.modules[import_name]
object.__setattr__(self, '_module', module) object.__setattr__(self, '_module', module)
@ -349,7 +349,7 @@ class _ModuleProxy:
if self._module is not None: if self._module is not None:
raise raise
import_name = f'pyglet.{self._module_name}' import_name = 'pyglet.%s' % self._module_name
__import__(import_name) __import__(import_name)
module = sys.modules[import_name] module = sys.modules[import_name]
object.__setattr__(self, '_module', module) object.__setattr__(self, '_module', module)

View File

@ -340,7 +340,9 @@ class ScreenMode:
self.screen = screen self.screen = screen
def __repr__(self): def __repr__(self):
return f'{self.__class__.__name__}(width={self.width!r}, height={self.height!r}, depth={self.depth!r}, rate={self.rate})' return '%s(width=%r, height=%r, depth=%r, rate=%r)' % (
self.__class__.__name__,
self.width, self.height, self.depth, self.rate)
class Canvas: class Canvas:

View File

@ -56,7 +56,7 @@ class HeadlessDisplay(Display):
if num_devices.value > 0: if num_devices.value > 0:
headless_device = pyglet.options['headless_device'] headless_device = pyglet.options['headless_device']
if headless_device < 0 or headless_device >= num_devices.value: if headless_device < 0 or headless_device >= num_devices.value:
raise ValueError(f'Invalid EGL devide id: {headless_device}') raise ValueError('Invalid EGL devide id: %d' % headless_device)
devices = (eglext.EGLDeviceEXT * num_devices.value)() devices = (eglext.EGLDeviceEXT * num_devices.value)()
eglext.eglQueryDevicesEXT(num_devices.value, devices, byref(num_devices)) eglext.eglQueryDevicesEXT(num_devices.value, devices, byref(num_devices))
self._display_connection = eglext.eglGetPlatformDisplayEXT( self._display_connection = eglext.eglGetPlatformDisplayEXT(

View File

@ -134,7 +134,9 @@ class Win32ScreenMode(ScreenMode):
self.scaling = mode.dmDisplayFixedOutput self.scaling = mode.dmDisplayFixedOutput
def __repr__(self): def __repr__(self):
return f'{self.__class__.__name__}(width={self.width!r}, height={self.height!r}, depth={self.depth!r}, rate={self.rate}, scaling={self.scaling})' return '%s(width=%r, height=%r, depth=%r, rate=%r, scaling=%r)' % (
self.__class__.__name__,
self.width, self.height, self.depth, self.rate, self.scaling)
class Win32Canvas(Canvas): class Win32Canvas(Canvas):
def __init__(self, display, hwnd, hdc): def __init__(self, display, hwnd, hdc):

View File

@ -120,11 +120,11 @@ class XlibDisplay(XlibSelectDevice, Display):
self._display = xlib.XOpenDisplay(name) self._display = xlib.XOpenDisplay(name)
if not self._display: if not self._display:
raise NoSuchDisplayException(f'Cannot connect to "{name}"') raise NoSuchDisplayException('Cannot connect to "%s"' % name)
screen_count = xlib.XScreenCount(self._display) screen_count = xlib.XScreenCount(self._display)
if x_screen >= screen_count: if x_screen >= screen_count:
raise NoSuchDisplayException(f'Display "{name}" has no screen {x_screen:d}') raise NoSuchDisplayException('Display "%s" has no screen %d' % (name, x_screen))
super(XlibDisplay, self).__init__() super(XlibDisplay, self).__init__()
self.name = name self.name = name
@ -274,8 +274,9 @@ class XlibScreen(Screen):
self.set_mode(self._initial_mode) self.set_mode(self._initial_mode)
def __repr__(self): def __repr__(self):
return f"{self.__class__.__name__}(display={self.display!r}, x={self.x}, y={self.y}, " \ return 'XlibScreen(display=%r, x=%d, y=%d, ' \
f"width={self.width}, height={self.height}, xinerama={self._xinerama})" 'width=%d, height=%d, xinerama=%d)' % \
(self.display, self.x, self.y, self.width, self.height, self._xinerama)

View File

@ -219,7 +219,7 @@ class EventDispatcher:
# Single magically named function # Single magically named function
name = obj.__name__ name = obj.__name__
if name not in self.event_types: if name not in self.event_types:
raise EventException(f'Unknown event "{name}"') raise EventException('Unknown event "%s"' % name)
if inspect.ismethod(obj): if inspect.ismethod(obj):
yield name, WeakMethod(obj, partial(self._remove_handler, name)) yield name, WeakMethod(obj, partial(self._remove_handler, name))
else: else:
@ -234,7 +234,7 @@ class EventDispatcher:
for name, handler in kwargs.items(): for name, handler in kwargs.items():
# Function for handling given event (no magic) # Function for handling given event (no magic)
if name not in self.event_types: if name not in self.event_types:
raise EventException(f'Unknown event "{name}"') raise EventException('Unknown event "%s"' % name)
if inspect.ismethod(handler): if inspect.ismethod(handler):
yield name, WeakMethod(handler, partial(self._remove_handler, name)) yield name, WeakMethod(handler, partial(self._remove_handler, name))
else: else:
@ -398,7 +398,7 @@ class EventDispatcher:
"EventDispatcher.register_event_type('event_name')." "EventDispatcher.register_event_type('event_name')."
) )
assert event_type in self.event_types, \ assert event_type in self.event_types, \
f"{event_type} not found in {self}.event_types == {self.event_types}" "%r not found in %r.event_types == %r" % (event_type, self, self.event_types)
invoked = False invoked = False

View File

@ -254,17 +254,17 @@ def check_palette(palette):
for i, t in enumerate(p): for i, t in enumerate(p):
if len(t) not in (3, 4): if len(t) not in (3, 4):
raise ProtocolError( raise ProtocolError(
f"palette entry {i}: entries must be 3- or 4-tuples.") "palette entry %d: entries must be 3- or 4-tuples." % i)
if len(t) == 3: if len(t) == 3:
seen_triple = True seen_triple = True
if seen_triple and len(t) == 4: if seen_triple and len(t) == 4:
raise ProtocolError( raise ProtocolError(
f"palette entry {i}: all 4-tuples must precede all 3-tuples") "palette entry %d: all 4-tuples must precede all 3-tuples" % i)
for x in t: for x in t:
if int(x) != x or not(0 <= x <= 255): if int(x) != x or not(0 <= x <= 255):
raise ProtocolError( raise ProtocolError(
f"palette entry {i}: " "palette entry %d: "
"values must be integer: 0 <= x <= 255") "values must be integer: 0 <= x <= 255" % i)
return p return p
@ -282,10 +282,12 @@ def check_sizes(size, width, height):
"size argument should be a pair (width, height)") "size argument should be a pair (width, height)")
if width is not None and width != size[0]: if width is not None and width != size[0]:
raise ProtocolError( raise ProtocolError(
f"size[0] ({size[0]}) and width ({width}) should match when both are used.") "size[0] (%r) and width (%r) should match when both are used."
% (size[0], width))
if height is not None and height != size[1]: if height is not None and height != size[1]:
raise ProtocolError( raise ProtocolError(
f"size[1] ({size[1]}) and height ({height}) should match when both are used.") "size[1] (%r) and height (%r) should match when both are used."
% (size[1], height))
return size return size
@ -305,17 +307,17 @@ def check_color(c, greyscale, which):
except TypeError: except TypeError:
c = (c,) c = (c,)
if len(c) != 1: if len(c) != 1:
raise ProtocolError(f"{which} for greyscale must be 1-tuple") raise ProtocolError("%s for greyscale must be 1-tuple" % which)
if not is_natural(c[0]): if not is_natural(c[0]):
raise ProtocolError( raise ProtocolError(
f"{which} colour for greyscale must be integer") "%s colour for greyscale must be integer" % which)
else: else:
if not (len(c) == 3 and if not (len(c) == 3 and
is_natural(c[0]) and is_natural(c[0]) and
is_natural(c[1]) and is_natural(c[1]) and
is_natural(c[2])): is_natural(c[2])):
raise ProtocolError( raise ProtocolError(
f"{which} colour must be a triple of integers") "%s colour must be a triple of integers" % which)
return c return c
@ -551,7 +553,8 @@ class Writer:
valid = is_natural(b) and 1 <= b <= 16 valid = is_natural(b) and 1 <= b <= 16
if not valid: if not valid:
raise ProtocolError( raise ProtocolError(
f"each bitdepth {bitdepth} must be a positive integer <= 16") "each bitdepth %r must be a positive integer <= 16" %
(bitdepth,))
# Calculate channels, and # Calculate channels, and
# expand bitdepth to be one element per channel. # expand bitdepth to be one element per channel.
@ -653,7 +656,8 @@ class Writer:
if wrong_length: if wrong_length:
# Note: row numbers start at 0. # Note: row numbers start at 0.
raise ProtocolError( raise ProtocolError(
f"Expected {vpr} values but got {len(row)} values, in row {i}") "Expected %d values but got %d values, in row %d" %
(vpr, len(row), i))
yield row yield row
if self.interlace: if self.interlace:
@ -664,7 +668,8 @@ class Writer:
nrows = self.write_passes(outfile, check_rows(rows)) nrows = self.write_passes(outfile, check_rows(rows))
if nrows != self.height: if nrows != self.height:
raise ProtocolError( raise ProtocolError(
f"rows supplied ({nrows}) does not match height ({self.height})") "rows supplied (%d) does not match height (%d)" %
(nrows, self.height))
return nrows return nrows
def write_passes(self, outfile, rows): def write_passes(self, outfile, rows):
@ -775,7 +780,8 @@ class Writer:
if self.rescale: if self.rescale:
write_chunk( write_chunk(
outfile, b'sBIT', outfile, b'sBIT',
struct.pack(f'{self.planes,* [s[0] for s in self.rescale]}B' )) struct.pack('%dB' % self.planes,
* [s[0] for s in self.rescale]))
# :chunk:order: Without a palette (PLTE chunk), # :chunk:order: Without a palette (PLTE chunk),
# ordering is relatively relaxed. # ordering is relatively relaxed.
@ -991,7 +997,7 @@ def unpack_rows(rows):
to being a sequence of bytes. to being a sequence of bytes.
""" """
for row in rows: for row in rows:
fmt = f'!{len(row)}' fmt = '!%dH' % len(row)
yield bytearray(struct.pack(fmt, *row)) yield bytearray(struct.pack(fmt, *row))
@ -1181,7 +1187,8 @@ def from_array(a, mode=None, info={}):
if bitdepth: if bitdepth:
if info.get("bitdepth") and bitdepth != info['bitdepth']: if info.get("bitdepth") and bitdepth != info['bitdepth']:
raise ProtocolError( raise ProtocolError(
f"bitdepth ({bitdepth}) should match bitdepth of info ({info[bitdepth]}).") "bitdepth (%d) should match bitdepth of info (%d)." %
(bitdepth, info['bitdepth']))
info['bitdepth'] = bitdepth info['bitdepth'] = bitdepth
# Fill in and/or check entries in *info*. # Fill in and/or check entries in *info*.
@ -1376,17 +1383,19 @@ class Reader:
data = self.file.read(length) data = self.file.read(length)
if len(data) != length: if len(data) != length:
raise ChunkError( raise ChunkError(
f'Chunk {type} too short for required {length} octets.') 'Chunk %s too short for required %i octets.'
% (type, length))
checksum = self.file.read(4) checksum = self.file.read(4)
if len(checksum) != 4: if len(checksum) != 4:
raise ChunkError(f'Chunk {type} too short for checksum.') raise ChunkError('Chunk %s too short for checksum.' % type)
verify = zlib.crc32(type) verify = zlib.crc32(type)
verify = zlib.crc32(data, verify) verify = zlib.crc32(data, verify)
verify = struct.pack('!I', verify) verify = struct.pack('!I', verify)
if checksum != verify: if checksum != verify:
(a, ) = struct.unpack('!I', checksum) (a, ) = struct.unpack('!I', checksum)
(b, ) = struct.unpack('!I', verify) (b, ) = struct.unpack('!I', verify)
message = f"Checksum error in {type.decode('ascii')} chunk: 0x{a:08X} != 0x{b:08X}." message = ("Checksum error in %s chunk: 0x%08X != 0x%08X."
% (type.decode('ascii'), a, b))
if lenient: if lenient:
warnings.warn(message, RuntimeWarning) warnings.warn(message, RuntimeWarning)
else: else:
@ -1530,7 +1539,7 @@ class Reader:
return bytearray(bs) return bytearray(bs)
if self.bitdepth == 16: if self.bitdepth == 16:
return array('H', return array('H',
struct.unpack(f'!{(len(bs) // 2)}H' , bs)) struct.unpack('!%dH' % (len(bs) // 2), bs))
assert self.bitdepth < 8 assert self.bitdepth < 8
if width is None: if width is None:
@ -1625,13 +1634,14 @@ class Reader:
'End of file whilst reading chunk length and type.') 'End of file whilst reading chunk length and type.')
length, type = struct.unpack('!I4s', x) length, type = struct.unpack('!I4s', x)
if length > 2 ** 31 - 1: if length > 2 ** 31 - 1:
raise FormatError(f'Chunk {type} is too large: {length}.') raise FormatError('Chunk %s is too large: %d.' % (type, length))
# Check that all bytes are in valid ASCII range. # Check that all bytes are in valid ASCII range.
# https://www.w3.org/TR/2003/REC-PNG-20031110/#5Chunk-layout # https://www.w3.org/TR/2003/REC-PNG-20031110/#5Chunk-layout
type_bytes = set(bytearray(type)) type_bytes = set(bytearray(type))
if not(type_bytes <= set(range(65, 91)) | set(range(97, 123))): if not(type_bytes <= set(range(65, 91)) | set(range(97, 123))):
raise FormatError( raise FormatError(
f'Chunk {list(type)} has invalid Chunk Type.') 'Chunk %r has invalid Chunk Type.'
% list(type))
return length, type return length, type
def process_chunk(self, lenient=False): def process_chunk(self, lenient=False):
@ -1663,17 +1673,18 @@ class Reader:
if self.compression != 0: if self.compression != 0:
raise FormatError( raise FormatError(
f"Unknown compression method {self.compression}") "Unknown compression method %d" % self.compression)
if self.filter != 0: if self.filter != 0:
raise FormatError( raise FormatError(
f"Unknown filter method {self.filter}," "Unknown filter method %d,"
" see http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ." " see http://www.w3.org/TR/2003/REC-PNG-20031110/#9Filters ."
) % self.filter)
if self.interlace not in (0, 1): if self.interlace not in (0, 1):
raise FormatError( raise FormatError(
f"Unknown interlace method {self.interlace}, see " "Unknown interlace method %d, see "
"http://www.w3.org/TR/2003/REC-PNG-20031110/#8InterlaceMethods" "http://www.w3.org/TR/2003/REC-PNG-20031110/#8InterlaceMethods"
" .") " ."
% self.interlace)
# Derived values # Derived values
# http://www.w3.org/TR/PNG/#6Colour-values # http://www.w3.org/TR/PNG/#6Colour-values
@ -1722,7 +1733,7 @@ class Reader:
"PLTE chunk is required before bKGD chunk.") "PLTE chunk is required before bKGD chunk.")
self.background = struct.unpack('B', data) self.background = struct.unpack('B', data)
else: else:
self.background = struct.unpack(f"!{self.color_planes}", self.background = struct.unpack("!%dH" % self.color_planes,
data) data)
except struct.error: except struct.error:
raise FormatError("bKGD chunk has incorrect length.") raise FormatError("bKGD chunk has incorrect length.")
@ -1741,10 +1752,11 @@ class Reader:
else: else:
if self.alpha: if self.alpha:
raise FormatError( raise FormatError(
f"tRNS chunk is not valid with colour type {self.color_type}.") "tRNS chunk is not valid with colour type %d." %
self.color_type)
try: try:
self.transparent = \ self.transparent = \
struct.unpack(f"!{self.color_planes}", data) struct.unpack("!%dH" % self.color_planes, data)
except struct.error: except struct.error:
raise FormatError("tRNS chunk has incorrect length.") raise FormatError("tRNS chunk has incorrect length.")
@ -1977,12 +1989,13 @@ class Reader:
pixels = itertrns(pixels) pixels = itertrns(pixels)
targetbitdepth = None targetbitdepth = None
if self.sbit: if self.sbit:
sbit = struct.unpack(f'{len(self.sbit)}', self.sbit) sbit = struct.unpack('%dB' % len(self.sbit), self.sbit)
targetbitdepth = max(sbit) targetbitdepth = max(sbit)
if targetbitdepth > info['bitdepth']: if targetbitdepth > info['bitdepth']:
raise Error(f'sBIT chunk {sbit!r} exceeds bitdepth {self.bitdepth}') raise Error('sBIT chunk %r exceeds bitdepth %d' %
(sbit, self.bitdepth))
if min(sbit) <= 0: if min(sbit) <= 0:
raise Error(f'sBIT chunk {sbit} has a 0-entry') raise Error('sBIT chunk %r has a 0-entry' % sbit)
if targetbitdepth: if targetbitdepth:
shift = info['bitdepth'] - targetbitdepth shift = info['bitdepth'] - targetbitdepth
info['bitdepth'] = targetbitdepth info['bitdepth'] = targetbitdepth
@ -2168,23 +2181,24 @@ def check_bitdepth_colortype(bitdepth, colortype):
""" """
if bitdepth not in (1, 2, 4, 8, 16): if bitdepth not in (1, 2, 4, 8, 16):
raise FormatError(f"invalid bit depth {bitdepth}") raise FormatError("invalid bit depth %d" % bitdepth)
if colortype not in (0, 2, 3, 4, 6): if colortype not in (0, 2, 3, 4, 6):
raise FormatError(f"invalid colour type {colortype}") raise FormatError("invalid colour type %d" % colortype)
# Check indexed (palettized) images have 8 or fewer bits # Check indexed (palettized) images have 8 or fewer bits
# per pixel; check only indexed or greyscale images have # per pixel; check only indexed or greyscale images have
# fewer than 8 bits per pixel. # fewer than 8 bits per pixel.
if colortype & 1 and bitdepth > 8: if colortype & 1 and bitdepth > 8:
raise FormatError( raise FormatError(
f"Indexed images (colour type {bitdepth}) cannot" "Indexed images (colour type %d) cannot"
f" have bitdepth > 8 (bit depth {colortype})." " have bitdepth > 8 (bit depth %d)."
" See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ." " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ."
) % (bitdepth, colortype))
if bitdepth < 8 and colortype not in (0, 3): if bitdepth < 8 and colortype not in (0, 3):
raise FormatError( raise FormatError(
f"Illegal combination of bit depth ({bitdepth})" "Illegal combination of bit depth (%d)"
f" and colour type ({colortype})." " and colour type (%d)."
" See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 .") " See http://www.w3.org/TR/2003/REC-PNG-20031110/#table111 ."
% (bitdepth, colortype))
def is_natural(x): def is_natural(x):

View File

@ -213,7 +213,7 @@ class FreeTypeFont(base.Font):
def _load_font_face_from_system(self): def _load_font_face_from_system(self):
match = get_fontconfig().find_font(self._name, self.size, self.bold, self.italic) match = get_fontconfig().find_font(self._name, self.size, self.bold, self.italic)
if not match: if not match:
raise base.FontException(f'Could not match font "{self._name}"') raise base.FontException('Could not match font "%s"' % self._name)
self.face = FreeTypeFace.from_fontconfig(match) self.face = FreeTypeFace.from_fontconfig(match)
@classmethod @classmethod
@ -258,7 +258,7 @@ class FreeTypeFace:
return cls(match.face) return cls(match.face)
else: else:
if not match.file: if not match.file:
raise base.FontException(f'No filename for "{match.name}"') raise base.FontException('No filename for "%s"' % match.name)
return cls.from_file(match.file) return cls.from_file(match.file)
@property @property

View File

@ -402,16 +402,16 @@ class TruetypeInfo:
# a fuckwit. # a fuckwit.
header = _read_cmap_format4Header(self._data, offset) header = _read_cmap_format4Header(self._data, offset)
seg_count = header.seg_count_x2 // 2 seg_count = header.seg_count_x2 // 2
array_size = struct.calcsize(f'>{seg_count}') array_size = struct.calcsize('>%dH' % seg_count)
end_count = self._read_array(f'>{seg_count}', end_count = self._read_array('>%dH' % seg_count,
offset + header.size) offset + header.size)
start_count = self._read_array(f'>{seg_count}', start_count = self._read_array('>%dH' % seg_count,
offset + header.size + array_size + 2) offset + header.size + array_size + 2)
id_delta = self._read_array(f'>{seg_count}', id_delta = self._read_array('>%dh' % seg_count,
offset + header.size + array_size + 2 + array_size) offset + header.size + array_size + 2 + array_size)
id_range_offset_address = \ id_range_offset_address = \
offset + header.size + array_size + 2 + array_size + array_size offset + header.size + array_size + 2 + array_size + array_size
id_range_offset = self._read_array(f'>{seg_count}', id_range_offset = self._read_array('>%dH' % seg_count,
id_range_offset_address) id_range_offset_address)
character_map = {} character_map = {}
for i in range(0, seg_count): for i in range(0, seg_count):
@ -475,7 +475,7 @@ def _read_table(*entries):
setattr(self, pname, pvalue) setattr(self, pname, pvalue)
def __repr__(self): def __repr__(self):
return '{'+', '.join([f'{pname} = {pvalue}' for pname, pvalue in self.pairs])+'}' return '{'+', '.join(['%s = %s' % (pname, pvalue) for pname, pvalue in self.pairs])+'}'
@staticmethod @staticmethod
def array(data, offset, count): def array(data, offset, count):

View File

@ -142,9 +142,9 @@ class GDIGlyphRenderer(Win32GlyphRenderer):
if _debug_font: if _debug_font:
_debug('%r.render(%s)' % (self, text)) _debug('%r.render(%s)' % (self, text))
_debug(f'abc.abcA = {abc.abcA}') _debug('abc.abcA = %r' % abc.abcA)
_debug(f'abc.abcB = {abc.abcB}') _debug('abc.abcB = %r' % abc.abcB)
_debug(f'abc.abcC = {abc.abcC}') _debug('abc.abcC = %r' % abc.abcC)
_debug('width = %r' % width) _debug('width = %r' % width)
_debug('height = %r' % height) _debug('height = %r' % height)
_debug('lsb = %r' % lsb) _debug('lsb = %r' % lsb)

View File

@ -515,7 +515,7 @@ if __name__ == '__main__':
print('\n'.join(fonts)) print('\n'.join(fonts))
if DEBUG: if DEBUG:
print(f"Total: {len(font_list())}") print("Total: %s" % len(font_list()))
# -- CHAPTER 2: WORK WITH FONT DIMENSIONS -- # -- CHAPTER 2: WORK WITH FONT DIMENSIONS --

View File

@ -120,12 +120,14 @@ class VertexDomain:
self.buffer_attributes = [] # list of (buffer, attributes) self.buffer_attributes = [] # list of (buffer, attributes)
for name, meta in attribute_meta.items(): for name, meta in attribute_meta.items():
assert meta['format'][0] in _gl_types, f"'{meta['format']}' is not a valid atrribute format for '{name}'."
location = meta['location'] location = meta['location']
count = meta['count'] count = meta['count']
gl_type = _gl_types[meta['format'][0]] gl_type = _gl_types[meta['format'][0]]
normalize = 'n' in meta['format'] normalize = 'n' in meta['format']
attribute = vertexattribute.VertexAttribute(name, location, count, gl_type, normalize) attribute = vertexattribute.VertexAttribute(name, location, count, gl_type, normalize)
self.attributes.append(attribute) self.attributes.append(attribute)
# Create buffer: # Create buffer:
attribute.buffer = MappableBufferObject(attribute.stride * self.allocator.capacity) attribute.buffer = MappableBufferObject(attribute.stride * self.allocator.capacity)
attribute.buffer.element_size = attribute.stride attribute.buffer.element_size = attribute.stride

View File

@ -79,7 +79,7 @@ def dump_python():
print('os.getcwd():', os.getcwd()) print('os.getcwd():', os.getcwd())
for key, value in os.environ.items(): for key, value in os.environ.items():
if key.startswith('PYGLET_'): if key.startswith('PYGLET_'):
print(f"os.environ['{key}']: {value}") print("os.environ['%s']: %s" % (key, value))
def dump_pyglet(): def dump_pyglet():
@ -89,7 +89,7 @@ def dump_pyglet():
print('pyglet.compat_platform:', pyglet.compat_platform) print('pyglet.compat_platform:', pyglet.compat_platform)
print('pyglet.__file__:', pyglet.__file__) print('pyglet.__file__:', pyglet.__file__)
for key, value in pyglet.options.items(): for key, value in pyglet.options.items():
print(f"pyglet.options['{key}'] = {value!r}") print("pyglet.options['%s'] = %r" % (key, value))
def dump_window(): def dump_window():
@ -103,10 +103,10 @@ def dump_window():
print('display:', repr(display)) print('display:', repr(display))
screens = display.get_screens() screens = display.get_screens()
for i, screen in enumerate(screens): for i, screen in enumerate(screens):
print(f'screens[{i}]: {screen!r}') print('screens[%d]: %r' % (i, screen))
window = pyglet.window.Window(visible=False) window = pyglet.window.Window(visible=False)
for key, value in window.config.get_gl_attributes(): for key, value in window.config.get_gl_attributes():
print(f"config['{key}'] = {value!r}") print("config['%s'] = %r" % (key, value))
print('context:', repr(window.context)) print('context:', repr(window.context))
_heading('window.context._info') _heading('window.context._info')
@ -207,9 +207,9 @@ def dump_wintab():
impl_version = wintab.get_implementation_version() impl_version = wintab.get_implementation_version()
spec_version = wintab.get_spec_version() spec_version = wintab.get_spec_version()
print('WinTab: {0} {1}.{2} (Spec {3}.{4})'.format(interface_name, print('WinTab: %s %d.%d (Spec %d.%d)' % (interface_name,
impl_version >> 8, impl_version & 0xff, impl_version >> 8, impl_version & 0xff,
spec_version >> 8, spec_version & 0xff)) spec_version >> 8, spec_version & 0xff))
def _try_dump(heading, func): def _try_dump(heading, func):

View File

@ -138,7 +138,7 @@ class LibraryLoader:
if self.platform.startswith('linux'): if self.platform.startswith('linux'):
for name in names: for name in names:
libname = self.find_library(name) libname = self.find_library(name)
platform_names.append(libname or f'lib{name}.so') platform_names.append(libname or 'lib%s.so' % name)
platform_names.extend(names) platform_names.extend(names)
for name in platform_names: for name in platform_names:
@ -165,7 +165,7 @@ class LibraryLoader:
if _debug_lib: if _debug_lib:
print(f"Unexpected error loading library {name}: {str(o)}") print(f"Unexpected error loading library {name}: {str(o)}")
raise ImportError(f'Library "{names[0]}" not found.') raise ImportError('Library "%s" not found.' % names[0])
def find_library(self, name): def find_library(self, name):
return ctypes.util.find_library(name) return ctypes.util.find_library(name)
@ -272,7 +272,7 @@ class MachOLibraryLoader(LibraryLoader):
lib = _TraceLibrary(lib) lib = _TraceLibrary(lib)
return lib return lib
raise ImportError(f"Can't find framework {name}.") raise ImportError("Can't find framework %s." % name)
class LinuxLibraryLoader(LibraryLoader): class LinuxLibraryLoader(LibraryLoader):

View File

@ -38,7 +38,7 @@ from ctypes import util
from .cocoatypes import * from .cocoatypes import *
__LP64__ = (8 * struct.calcsize("P") == 64) __LP64__ = (8*struct.calcsize("P") == 64)
__i386__ = (platform.machine() == 'i386') __i386__ = (platform.machine() == 'i386')
__arm64__ = (platform.machine() == 'arm64') __arm64__ = (platform.machine() == 'arm64')
@ -332,7 +332,7 @@ objc.object_getClassName.argtypes = [c_void_p]
# Ivar object_getInstanceVariable(id obj, const char *name, void **outValue) # Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)
objc.object_getInstanceVariable.restype = c_void_p objc.object_getInstanceVariable.restype = c_void_p
objc.object_getInstanceVariable.argtypes = [c_void_p, c_char_p, c_void_p] objc.object_getInstanceVariable.argtypes=[c_void_p, c_char_p, c_void_p]
# id object_getIvar(id object, Ivar ivar) # id object_getIvar(id object, Ivar ivar)
objc.object_getIvar.restype = c_void_p objc.object_getIvar.restype = c_void_p
@ -366,10 +366,8 @@ objc.property_getName.argtypes = [c_void_p]
objc.protocol_conformsToProtocol.restype = c_bool objc.protocol_conformsToProtocol.restype = c_bool
objc.protocol_conformsToProtocol.argtypes = [c_void_p, c_void_p] objc.protocol_conformsToProtocol.argtypes = [c_void_p, c_void_p]
class OBJC_METHOD_DESCRIPTION(Structure): class OBJC_METHOD_DESCRIPTION(Structure):
_fields_ = [("name", c_void_p), ("types", c_char_p)] _fields_ = [ ("name", c_void_p), ("types", c_char_p) ]
# struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount) # struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount)
# You must free() the returned array. # You must free() the returned array.
@ -409,7 +407,6 @@ objc.sel_isEqual.argtypes = [c_void_p, c_void_p]
objc.sel_registerName.restype = c_void_p objc.sel_registerName.restype = c_void_p
objc.sel_registerName.argtypes = [c_char_p] objc.sel_registerName.argtypes = [c_char_p]
###################################################################### ######################################################################
def ensure_bytes(x): def ensure_bytes(x):
@ -417,25 +414,20 @@ def ensure_bytes(x):
return x return x
return x.encode('ascii') return x.encode('ascii')
###################################################################### ######################################################################
def get_selector(name): def get_selector(name):
return c_void_p(objc.sel_registerName(ensure_bytes(name))) return c_void_p(objc.sel_registerName(ensure_bytes(name)))
def get_class(name): def get_class(name):
return c_void_p(objc.objc_getClass(ensure_bytes(name))) return c_void_p(objc.objc_getClass(ensure_bytes(name)))
def get_object_class(obj): def get_object_class(obj):
return c_void_p(objc.object_getClass(obj)) return c_void_p(objc.object_getClass(obj))
def get_metaclass(name): def get_metaclass(name):
return c_void_p(objc.objc_getMetaClass(ensure_bytes(name))) return c_void_p(objc.objc_getMetaClass(ensure_bytes(name)))
def get_superclass_of_object(obj): def get_superclass_of_object(obj):
cls = c_void_p(objc.object_getClass(obj)) cls = c_void_p(objc.object_getClass(obj))
return c_void_p(objc.class_getSuperclass(cls)) return c_void_p(objc.class_getSuperclass(cls))
@ -454,7 +446,6 @@ def x86_should_use_stret(restype):
return False return False
return True return True
# http://www.sealiesoftware.com/blog/archive/2008/11/16/objc_explain_objc_msgSend_fpret.html # http://www.sealiesoftware.com/blog/archive/2008/11/16/objc_explain_objc_msgSend_fpret.html
def should_use_fpret(restype): def should_use_fpret(restype):
"""Determine if objc_msgSend_fpret is required to return a floating point type.""" """Determine if objc_msgSend_fpret is required to return a floating point type."""
@ -468,7 +459,6 @@ def should_use_fpret(restype):
return True return True
return False return False
# By default, assumes that restype is c_void_p # By default, assumes that restype is c_void_p
# and that all arguments are wrapped inside c_void_p. # and that all arguments are wrapped inside c_void_p.
# Use the restype and argtypes keyword arguments to # Use the restype and argtypes keyword arguments to
@ -480,7 +470,7 @@ def send_message(receiver, selName, *args, **kwargs):
receiver = get_class(receiver) receiver = get_class(receiver)
selector = get_selector(selName) selector = get_selector(selName)
restype = kwargs.get('restype', c_void_p) restype = kwargs.get('restype', c_void_p)
# print('send_message', receiver, selName, args, kwargs) #print('send_message', receiver, selName, args, kwargs)
argtypes = kwargs.get('argtypes', []) argtypes = kwargs.get('argtypes', [])
# Choose the correct version of objc_msgSend based on return type. # Choose the correct version of objc_msgSend based on return type.
if should_use_fpret(restype): if should_use_fpret(restype):
@ -499,14 +489,11 @@ def send_message(receiver, selName, *args, **kwargs):
result = c_void_p(result) result = c_void_p(result)
return result return result
class OBJC_SUPER(Structure): class OBJC_SUPER(Structure):
_fields_ = [('receiver', c_void_p), ('class', c_void_p)] _fields_ = [ ('receiver', c_void_p), ('class', c_void_p) ]
OBJC_SUPER_PTR = POINTER(OBJC_SUPER) OBJC_SUPER_PTR = POINTER(OBJC_SUPER)
# http://stackoverflow.com/questions/3095360/what-exactly-is-super-in-objective-c # http://stackoverflow.com/questions/3095360/what-exactly-is-super-in-objective-c
# #
# `superclass_name` is optional and can be used to force finding the superclass # `superclass_name` is optional and can be used to force finding the superclass
@ -534,12 +521,10 @@ def send_super(receiver, selName, *args, superclass_name=None, **kwargs):
result = c_void_p(result) result = c_void_p(result)
return result return result
###################################################################### ######################################################################
cfunctype_table = {} cfunctype_table = {}
def parse_type_encoding(encoding): def parse_type_encoding(encoding):
"""Takes a type encoding string and outputs a list of the separated type codes. """Takes a type encoding string and outputs a list of the separated type codes.
Currently does not handle unions or bitfields and strips out any field width Currently does not handle unions or bitfields and strips out any field width
@ -551,7 +536,7 @@ def parse_type_encoding(encoding):
parse_type_encoding('{CGSize=dd}40@0:8{CGSize=dd}16Q32') --> ['{CGSize=dd}', '@', ':', '{CGSize=dd}', 'Q'] parse_type_encoding('{CGSize=dd}40@0:8{CGSize=dd}16Q32') --> ['{CGSize=dd}', '@', ':', '{CGSize=dd}', 'Q']
""" """
type_encodings = [] type_encodings = []
brace_count = 0 # number of unclosed curly braces brace_count = 0 # number of unclosed curly braces
bracket_count = 0 # number of unclosed square brackets bracket_count = 0 # number of unclosed square brackets
typecode = b'' typecode = b''
for c in encoding: for c in encoding:
@ -570,7 +555,7 @@ def parse_type_encoding(encoding):
elif c == b'}': elif c == b'}':
typecode += c typecode += c
brace_count -= 1 brace_count -= 1
assert (brace_count >= 0) assert(brace_count >= 0)
elif c == b'[': elif c == b'[':
# Check if this marked the end of previous type code. # Check if this marked the end of previous type code.
if typecode and typecode[-1:] != b'^' and brace_count == 0 and bracket_count == 0: if typecode and typecode[-1:] != b'^' and brace_count == 0 and bracket_count == 0:
@ -581,7 +566,7 @@ def parse_type_encoding(encoding):
elif c == b']': elif c == b']':
typecode += c typecode += c
bracket_count -= 1 bracket_count -= 1
assert (bracket_count >= 0) assert(bracket_count >= 0)
elif brace_count or bracket_count: elif brace_count or bracket_count:
# Anything encountered while inside braces or brackets gets stuck on. # Anything encountered while inside braces or brackets gets stuck on.
typecode += c typecode += c
@ -619,12 +604,12 @@ def cfunctype_for_encoding(encoding):
return cfunctype_table[encoding] return cfunctype_table[encoding]
# Otherwise, create a new CFUNCTYPE for the encoding. # Otherwise, create a new CFUNCTYPE for the encoding.
typecodes = {b'c': c_char, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong, typecodes = {b'c':c_char, b'i':c_int, b's':c_short, b'l':c_long, b'q':c_longlong,
b'C': c_ubyte, b'I': c_uint, b'S': c_ushort, b'L': c_ulong, b'Q': c_ulonglong, b'C':c_ubyte, b'I':c_uint, b'S':c_ushort, b'L':c_ulong, b'Q':c_ulonglong,
b'f': c_float, b'd': c_double, b'B': c_bool, b'v': None, b'*': c_char_p, b'f':c_float, b'd':c_double, b'B':c_bool, b'v':None, b'*':c_char_p,
b'@': c_void_p, b'#': c_void_p, b':': c_void_p, NSPointEncoding: NSPoint, b'@':c_void_p, b'#':c_void_p, b':':c_void_p, NSPointEncoding:NSPoint,
NSSizeEncoding: NSSize, NSRectEncoding: NSRect, NSRangeEncoding: NSRange, NSSizeEncoding:NSSize, NSRectEncoding:NSRect, NSRangeEncoding:NSRange,
PyObjectEncoding: py_object} PyObjectEncoding:py_object}
argtypes = [] argtypes = []
for code in parse_type_encoding(encoding): for code in parse_type_encoding(encoding):
if code in typecodes: if code in typecodes:
@ -642,7 +627,6 @@ def cfunctype_for_encoding(encoding):
cfunctype_table[encoding] = cfunctype cfunctype_table[encoding] = cfunctype
return cfunctype return cfunctype
###################################################################### ######################################################################
# After calling create_subclass, you must first register # After calling create_subclass, you must first register
@ -654,11 +638,9 @@ def create_subclass(superclass, name):
superclass = get_class(superclass) superclass = get_class(superclass)
return c_void_p(objc.objc_allocateClassPair(superclass, ensure_bytes(name), 0)) return c_void_p(objc.objc_allocateClassPair(superclass, ensure_bytes(name), 0))
def register_subclass(subclass): def register_subclass(subclass):
objc.objc_registerClassPair(subclass) objc.objc_registerClassPair(subclass)
# types is a string encoding the argument types of the method. # types is a string encoding the argument types of the method.
# The first type code of types is the return type (e.g. 'v' if void) # The first type code of types is the return type (e.g. 'v' if void)
# The second type code must be '@' for id self. # The second type code must be '@' for id self.
@ -666,8 +648,8 @@ def register_subclass(subclass):
# Additional type codes are for types of other arguments if any. # Additional type codes are for types of other arguments if any.
def add_method(cls, selName, method, types): def add_method(cls, selName, method, types):
type_encodings = parse_type_encoding(types) type_encodings = parse_type_encoding(types)
assert (type_encodings[1] == b'@') # ensure id self typecode assert(type_encodings[1] == b'@') # ensure id self typecode
assert (type_encodings[2] == b':') # ensure SEL cmd typecode assert(type_encodings[2] == b':') # ensure SEL cmd typecode
selector = get_selector(selName) selector = get_selector(selName)
cfunctype = cfunctype_for_encoding(types) cfunctype = cfunctype_for_encoding(types)
imp = cfunctype(method) imp = cfunctype(method)
@ -675,22 +657,18 @@ def add_method(cls, selName, method, types):
objc.class_addMethod(cls, selector, imp, types) objc.class_addMethod(cls, selector, imp, types)
return imp return imp
def add_ivar(cls, name, vartype): def add_ivar(cls, name, vartype):
return objc.class_addIvar(cls, ensure_bytes(name), sizeof(vartype), alignment(vartype), encoding_for_ctype(vartype)) return objc.class_addIvar(cls, ensure_bytes(name), sizeof(vartype), alignment(vartype), encoding_for_ctype(vartype))
def set_instance_variable(obj, varname, value, vartype): def set_instance_variable(obj, varname, value, vartype):
objc.object_setInstanceVariable.argtypes = [c_void_p, c_char_p, vartype] objc.object_setInstanceVariable.argtypes = [c_void_p, c_char_p, vartype]
objc.object_setInstanceVariable(obj, ensure_bytes(varname), value) objc.object_setInstanceVariable(obj, ensure_bytes(varname), value)
def get_instance_variable(obj, varname, vartype): def get_instance_variable(obj, varname, vartype):
variable = vartype() variable = vartype()
objc.object_getInstanceVariable(obj, ensure_bytes(varname), byref(variable)) objc.object_getInstanceVariable(obj, ensure_bytes(varname), byref(variable))
return variable.value return variable.value
###################################################################### ######################################################################
class ObjCMethod: class ObjCMethod:
@ -699,13 +677,13 @@ class ObjCMethod:
# Note, need to map 'c' to c_byte rather than c_char, because otherwise # Note, need to map 'c' to c_byte rather than c_char, because otherwise
# ctypes converts the value into a one-character string which is generally # ctypes converts the value into a one-character string which is generally
# not what we want at all, especially when the 'c' represents a bool var. # not what we want at all, especially when the 'c' represents a bool var.
typecodes = {b'c': c_byte, b'i': c_int, b's': c_short, b'l': c_long, b'q': c_longlong, typecodes = {b'c':c_byte, b'i':c_int, b's':c_short, b'l':c_long, b'q':c_longlong,
b'C': c_ubyte, b'I': c_uint, b'S': c_ushort, b'L': c_ulong, b'Q': c_ulonglong, b'C':c_ubyte, b'I':c_uint, b'S':c_ushort, b'L':c_ulong, b'Q':c_ulonglong,
b'f': c_float, b'd': c_double, b'B': c_bool, b'v': None, b'Vv': None, b'*': c_char_p, b'f':c_float, b'd':c_double, b'B':c_bool, b'v':None, b'Vv':None, b'*':c_char_p,
b'@': c_void_p, b'#': c_void_p, b':': c_void_p, b'^v': c_void_p, b'?': c_void_p, b'@':c_void_p, b'#':c_void_p, b':':c_void_p, b'^v':c_void_p, b'?':c_void_p,
NSPointEncoding: NSPoint, NSSizeEncoding: NSSize, NSRectEncoding: NSRect, NSPointEncoding:NSPoint, NSSizeEncoding:NSSize, NSRectEncoding:NSRect,
NSRangeEncoding: NSRange, NSRangeEncoding:NSRange,
PyObjectEncoding: py_object} PyObjectEncoding:py_object}
cfunctype_table = {} cfunctype_table = {}
@ -728,7 +706,7 @@ class ObjCMethod:
try: try:
self.argtypes = [self.ctype_for_encoding(t) for t in self.argument_types] self.argtypes = [self.ctype_for_encoding(t) for t in self.argument_types]
except: except:
# print(f'no argtypes encoding for {self.name} ({self.argument_types})') #print('no argtypes encoding for %s (%s)' % (self.name, self.argument_types))
self.argtypes = None self.argtypes = None
# Get types for the return type. # Get types for the return type.
try: try:
@ -739,7 +717,7 @@ class ObjCMethod:
else: else:
self.restype = self.ctype_for_encoding(self.return_type) self.restype = self.ctype_for_encoding(self.return_type)
except: except:
# print(f'no restype encoding for {self.name} ({self.return_type})') #print('no restype encoding for %s (%s)' % (self.name, self.return_type))
self.restype = None self.restype = None
self.func = None self.func = None
@ -808,7 +786,6 @@ class ObjCMethod:
'encoding = ' + str(self.encoding)) 'encoding = ' + str(self.encoding))
raise raise
###################################################################### ######################################################################
class ObjCBoundMethod: class ObjCBoundMethod:
@ -827,7 +804,6 @@ class ObjCBoundMethod:
"""Call the method with the given arguments.""" """Call the method with the given arguments."""
return self.method(self.objc_id, *args) return self.method(self.objc_id, *args)
###################################################################### ######################################################################
class ObjCClass: class ObjCClass:
@ -865,9 +841,9 @@ class ObjCClass:
objc_class = super(ObjCClass, cls).__new__(cls) objc_class = super(ObjCClass, cls).__new__(cls)
objc_class.ptr = ptr objc_class.ptr = ptr
objc_class.name = name objc_class.name = name
objc_class.instance_methods = {} # mapping of name -> instance method objc_class.instance_methods = {} # mapping of name -> instance method
objc_class.class_methods = {} # mapping of name -> class method objc_class.class_methods = {} # mapping of name -> class method
objc_class._as_parameter_ = ptr # for ctypes argument passing objc_class._as_parameter_ = ptr # for ctypes argument passing
# Store the new class in dictionary of registered classes. # Store the new class in dictionary of registered classes.
cls._registered_classes[name] = objc_class cls._registered_classes[name] = objc_class
@ -951,7 +927,6 @@ class ObjCClass:
# Otherwise, raise an exception. # Otherwise, raise an exception.
raise AttributeError('ObjCClass %s has no attribute %s' % (self.name, name)) raise AttributeError('ObjCClass %s has no attribute %s' % (self.name, name))
###################################################################### ######################################################################
class ObjCInstance: class ObjCInstance:
@ -1033,7 +1008,6 @@ class ObjCInstance:
# Otherwise raise an exception. # Otherwise raise an exception.
raise AttributeError('ObjCInstance %s has no attribute %s' % (self.objc_class.name, name)) raise AttributeError('ObjCInstance %s has no attribute %s' % (self.objc_class.name, name))
###################################################################### ######################################################################
def convert_method_arguments(encoding, args): def convert_method_arguments(encoding, args):
@ -1050,7 +1024,6 @@ def convert_method_arguments(encoding, args):
new_args.append(a) new_args.append(a)
return new_args return new_args
# ObjCSubclass is used to define an Objective-C subclass of an existing # ObjCSubclass is used to define an Objective-C subclass of an existing
# class registered with the runtime. When you create an instance of # class registered with the runtime. When you create an instance of
# ObjCSubclass, it registers the new subclass with the Objective-C # ObjCSubclass, it registers the new subclass with the Objective-C
@ -1147,12 +1120,10 @@ class ObjCSubclass:
typecodes = parse_type_encoding(encoding) typecodes = parse_type_encoding(encoding)
typecodes.insert(1, b'@:') typecodes.insert(1, b'@:')
encoding = b''.join(typecodes) encoding = b''.join(typecodes)
def decorator(f): def decorator(f):
name = f.__name__.replace('_', ':') name = f.__name__.replace('_', ':')
self.add_method(f, name, encoding) self.add_method(f, name, encoding)
return f return f
return decorator return decorator
def method(self, encoding): def method(self, encoding):
@ -1162,7 +1133,6 @@ class ObjCSubclass:
typecodes = parse_type_encoding(encoding) typecodes = parse_type_encoding(encoding)
typecodes.insert(1, b'@:') typecodes.insert(1, b'@:')
encoding = b''.join(typecodes) encoding = b''.join(typecodes)
def decorator(f): def decorator(f):
def objc_method(objc_self, objc_cmd, *args): def objc_method(objc_self, objc_cmd, *args):
py_self = ObjCInstance(objc_self) py_self = ObjCInstance(objc_self)
@ -1174,11 +1144,9 @@ class ObjCSubclass:
elif isinstance(result, ObjCInstance): elif isinstance(result, ObjCInstance):
result = result.ptr.value result = result.ptr.value
return result return result
name = f.__name__.replace('_', ':') name = f.__name__.replace('_', ':')
self.add_method(objc_method, name, encoding) self.add_method(objc_method, name, encoding)
return objc_method return objc_method
return decorator return decorator
def classmethod(self, encoding): def classmethod(self, encoding):
@ -1188,7 +1156,6 @@ class ObjCSubclass:
typecodes = parse_type_encoding(encoding) typecodes = parse_type_encoding(encoding)
typecodes.insert(1, b'@:') typecodes.insert(1, b'@:')
encoding = b''.join(typecodes) encoding = b''.join(typecodes)
def decorator(f): def decorator(f):
def objc_class_method(objc_cls, objc_cmd, *args): def objc_class_method(objc_cls, objc_cmd, *args):
py_cls = ObjCClass(objc_cls) py_cls = ObjCClass(objc_cls)
@ -1200,14 +1167,11 @@ class ObjCSubclass:
elif isinstance(result, ObjCInstance): elif isinstance(result, ObjCInstance):
result = result.ptr.value result = result.ptr.value
return result return result
name = f.__name__.replace('_', ':') name = f.__name__.replace('_', ':')
self.add_class_method(objc_class_method, name, encoding) self.add_class_method(objc_class_method, name, encoding)
return objc_class_method return objc_class_method
return decorator return decorator
###################################################################### ######################################################################
# Instances of DeallocationObserver are associated with every # Instances of DeallocationObserver are associated with every

View File

@ -87,7 +87,7 @@ def get_audio_driver():
break break
except Exception: except Exception:
if _debug: if _debug:
print(f'Error importing driver {driver_name}:') print('Error importing driver %s:' % driver_name)
import traceback import traceback
traceback.print_exc() traceback.print_exc()
else: else:

View File

@ -210,7 +210,7 @@ class PulseAudioPlayer(AbstractAudioPlayer):
def _write_to_stream(self, nbytes=None): def _write_to_stream(self, nbytes=None):
if nbytes is None: if nbytes is None:
nbytes = self.stream.writable_size nbytes = self.stream.writable_size
assert _debug(f'PulseAudioPlayer: Requested to write {nbytes} bytes to stream') assert _debug('PulseAudioPlayer: Requested to write %d bytes to stream' % nbytes)
seek_mode = pa.PA_SEEK_RELATIVE seek_mode = pa.PA_SEEK_RELATIVE
if self._clear_write: if self._clear_write:

View File

@ -101,7 +101,7 @@ class MediaThread:
Time to wait, in seconds. Time to wait, in seconds.
""" """
assert _debug(f'MediaThread.sleep({timeout!r})') assert _debug('MediaThread.sleep(%r)' % timeout)
with self._condition: with self._condition:
if not self._stopped: if not self._stopped:
self._condition.wait(timeout) self._condition.wait(timeout)

View File

@ -184,16 +184,16 @@ def get_settings_path(name):
if 'APPDATA' in os.environ: if 'APPDATA' in os.environ:
return os.path.join(os.environ['APPDATA'], name) return os.path.join(os.environ['APPDATA'], name)
else: else:
return os.path.expanduser(f'~/{name}') return os.path.expanduser('~/%s' % name)
elif pyglet.compat_platform == 'darwin': elif pyglet.compat_platform == 'darwin':
return os.path.expanduser(f'~/Library/Application Support/{name}') return os.path.expanduser('~/Library/Application Support/%s' % name)
elif pyglet.compat_platform.startswith('linux'): elif pyglet.compat_platform.startswith('linux'):
if 'XDG_CONFIG_HOME' in os.environ: if 'XDG_CONFIG_HOME' in os.environ:
return os.path.join(os.environ['XDG_CONFIG_HOME'], name) return os.path.join(os.environ['XDG_CONFIG_HOME'], name)
else: else:
return os.path.expanduser(f'~/.config/{name}') return os.path.expanduser('~/.config/%s' % name)
else: else:
return os.path.expanduser(f'~/.{name}') return os.path.expanduser('~/.%s' % name)
def get_data_path(name): def get_data_path(name):
@ -225,16 +225,16 @@ def get_data_path(name):
if 'APPDATA' in os.environ: if 'APPDATA' in os.environ:
return os.path.join(os.environ['APPDATA'], name) return os.path.join(os.environ['APPDATA'], name)
else: else:
return os.path.expanduser(f'~/{name}') return os.path.expanduser('~/%s' % name)
elif pyglet.compat_platform == 'darwin': elif pyglet.compat_platform == 'darwin':
return os.path.expanduser(f'~/Library/Application Support/{name}') return os.path.expanduser('~/Library/Application Support/%s' % name)
elif pyglet.compat_platform.startswith('linux'): elif pyglet.compat_platform.startswith('linux'):
if 'XDG_DATA_HOME' in os.environ: if 'XDG_DATA_HOME' in os.environ:
return os.path.join(os.environ['XDG_DATA_HOME'], name) return os.path.join(os.environ['XDG_DATA_HOME'], name)
else: else:
return os.path.expanduser(f'~/.local/share/{name}') return os.path.expanduser('~/.local/share/%s' % name)
else: else:
return os.path.expanduser(f'~/.{name}') return os.path.expanduser('~/.%s' % name)
class Location: class Location:

View File

@ -63,7 +63,7 @@ properties determine the sprite's :py:attr:`~pyglet.sprite.Sprite.rotation`,
:py:attr:`~pyglet.sprite.Sprite.scale` and :py:attr:`~pyglet.sprite.Sprite.scale` and
:py:attr:`~pyglet.sprite.Sprite.opacity`. :py:attr:`~pyglet.sprite.Sprite.opacity`.
By default sprite coordinates are restricted to integer values to avoid By default, sprite coordinates are restricted to integer values to avoid
sub-pixel artifacts. If you require to use floats, for example for smoother sub-pixel artifacts. If you require to use floats, for example for smoother
animations, you can set the ``subpixel`` parameter to ``True`` when creating animations, you can set the ``subpixel`` parameter to ``True`` when creating
the sprite (:since: pyglet 1.2). the sprite (:since: pyglet 1.2).
@ -256,7 +256,7 @@ class SpriteGroup(graphics.Group):
def __eq__(self, other): def __eq__(self, other):
return (other.__class__ is self.__class__ and return (other.__class__ is self.__class__ and
self.program is other.program and self.program is other.program and
self.parent is other.parent and self.parent == other.parent and
self.texture.target == other.texture.target and self.texture.target == other.texture.target and
self.texture.id == other.texture.id and self.texture.id == other.texture.id and
self.blend_src == other.blend_src and self.blend_src == other.blend_src and

View File

@ -148,7 +148,7 @@ def get_decoder(filename, mimetype=None):
from pyglet.text.formats import attributed from pyglet.text.formats import attributed
return attributed.AttributedTextDecoder() return attributed.AttributedTextDecoder()
else: else:
raise DocumentDecodeException(f'Unknown format "{mimetype}"') raise DocumentDecodeException('Unknown format "%s"' % mimetype)
def load(filename, file=None, mimetype=None): def load(filename, file=None, mimetype=None):

View File

@ -487,7 +487,7 @@ class AbstractDocument(event.EventDispatcher):
for element in self._elements: for element in self._elements:
if element._position == position: if element._position == position:
return element return element
raise RuntimeError(f'No element at position {position}') raise RuntimeError('No element at position %d' % position)
def set_style(self, start, end, attributes): def set_style(self, start, end, attributes):
"""Set text style of some or all of the document. """Set text style of some or all of the document.

View File

@ -236,7 +236,7 @@ class OrderedListBuilder(ListBuilder):
mark = '?' mark = '?'
if self.numbering == 'A': if self.numbering == 'A':
mark = mark.upper() mark = mark.upper()
return f'{self.prefix}{mark}{self.suffix}' return '%s%s%s' % (self.prefix, mark, self.suffix)
elif self.numbering in 'iI': elif self.numbering in 'iI':
try: try:
mark = _int_to_roman(value) mark = _int_to_roman(value)
@ -244,9 +244,9 @@ class OrderedListBuilder(ListBuilder):
mark = '?' mark = '?'
if self.numbering == 'i': if self.numbering == 'i':
mark = mark.lower() mark = mark.lower()
return f'{self.prefix}{mark}{self.suffix}' return '%s%s%s' % (self.prefix, mark, self.suffix)
else: else:
return f'{self.prefix}{value}{self.suffix}' return '%s%d%s' % (self.prefix, value, self.suffix)
class StructuredTextDecoder(pyglet.text.DocumentDecoder): class StructuredTextDecoder(pyglet.text.DocumentDecoder):

View File

@ -180,7 +180,7 @@ def _parse_distance(distance, dpi):
return int(distance) return int(distance)
match = _distance_re.match(distance) match = _distance_re.match(distance)
assert match, f'Could not parse distance {distance}' assert match, 'Could not parse distance %s' % distance
if not match: if not match:
return 0 return 0
@ -199,7 +199,7 @@ def _parse_distance(distance, dpi):
elif unit == 'cm': elif unit == 'cm':
return int(value * dpi * 0.393700787) return int(value * dpi * 0.393700787)
else: else:
assert False, f'Unknown distance unit {unit}' assert False, 'Unknown distance unit %s' % unit
class _Line: class _Line:
@ -225,7 +225,7 @@ class _Line:
self.boxes = [] self.boxes = []
def __repr__(self): def __repr__(self):
return f'_Line({self.boxes})' return '_Line(%r)' % self.boxes
def add_box(self, box): def add_box(self, box):
self.boxes.append(box) self.boxes.append(box)
@ -460,7 +460,7 @@ class _GlyphBox(_AbstractBox):
return position return position
def __repr__(self): def __repr__(self):
return f'_GlyphBox({self.glyphs})' return '_GlyphBox(%r)' % self.glyphs
class _InlineElementBox(_AbstractBox): class _InlineElementBox(_AbstractBox):
@ -495,7 +495,7 @@ class _InlineElementBox(_AbstractBox):
return 1 return 1
def __repr__(self): def __repr__(self):
return f'_InlineElementBox({self.element})' return '_InlineElementBox(%r)' % self.element
class _InvalidRange: class _InvalidRange:
@ -1131,8 +1131,8 @@ class TextLayout:
dz = z - self._z dz = z - self._z
for vertex_list in self._vertex_lists: for vertex_list in self._vertex_lists:
vertices = vertex_list.position[:] vertices = vertex_list.position[:]
vertices[::2] = [x + dx for x in vertices[::2]] vertices[::3] = [x + dx for x in vertices[::3]]
vertices[1::2] = [y + dy for y in vertices[1::2]] vertices[1::3] = [y + dy for y in vertices[1::3]]
vertices[2::3] = [z + dz for z in vertices[2::3]] vertices[2::3] = [z + dz for z in vertices[2::3]]
vertex_list.position[:] = vertices vertex_list.position[:] = vertices
self._x = x self._x = x
@ -2046,8 +2046,6 @@ class IncrementalTextLayout(TextLayout, EventDispatcher):
self._update_scissor_area() self._update_scissor_area()
def _update_scissor_area(self): def _update_scissor_area(self):
if not self.document.text:
return
area = self._get_left(), self._get_bottom(self._get_lines()), self._width, self._height area = self._get_left(), self._get_bottom(self._get_lines()), self._width, self._height
for group in self.group_cache.values(): for group in self.group_cache.values():
group.scissor_area = area group.scissor_area = area
@ -2127,6 +2125,7 @@ class IncrementalTextLayout(TextLayout, EventDispatcher):
self.invalid_flow.is_invalid() or self.invalid_flow.is_invalid() or
self.invalid_lines.is_invalid()) self.invalid_lines.is_invalid())
len_groups = len(self.group_cache)
# Special care if there is no text: # Special care if there is no text:
if not self.glyphs: if not self.glyphs:
for line in self.lines: for line in self.lines:
@ -2145,6 +2144,11 @@ class IncrementalTextLayout(TextLayout, EventDispatcher):
self._update_visible_lines() self._update_visible_lines()
self._update_vertex_lists() self._update_vertex_lists()
# Update group cache areas if the count has changed. Usually if it starts with no text.
# Group cache is only cleared in a regular TextLayout. May need revisiting if that changes.
if len_groups != len(self.group_cache):
self._update_scissor_area()
if trigger_update_event: if trigger_update_event:
self.dispatch_event('on_layout_update') self.dispatch_event('on_layout_update')

View File

@ -44,7 +44,7 @@ class _Run:
self.count = count self.count = count
def __repr__(self): def __repr__(self):
return f'Run({self.value}, {self.count})' return 'Run(%r, %d)' % (self.value, self.count)
class RunList: class RunList: