peng3d.util - Utility Functions and Classes

class peng3d.util.WatchingList(l, callback=None)[source]

Subclass of list() implementing a watched list.

A WatchingList will call the given callback with a reference to itself whenever it is modified. Internally, the callback is stored as a weak reference, meaning that the creator should keep a reference around.

This class is used in peng3d.gui.widgets.BasicWidget() to allow for modifying single coordinates of the pos and size properties.

peng3d.util.register_pyglet_handler(peng, func, event, raiseErrors=False)[source]

Registers the given pyglet-style event handler for the given pyglet event.

This function allows pyglet-style event handlers to receive events bridged through the peng3d event system. Internally, this function creates a lambda function that decodes the arguments and then calls the pyglet-style event handler.

The raiseErrors flag is passed through to the peng3d event system and will cause any errors raised by this handler to be ignored.

See also

See addEventListener() for more information.

class peng3d.util.ActionDispatcher[source]

Helper Class to be used to enable action support.

Actions are simple callbacks that are specific to the instance they are registered with.

To be able to use actions, a class must be a subclass of ActionDispatcher().

Creation of required data structures is handled automatically when the first action is added.

Internally, this object uses the actions attribute to store a map of action names to a list of callbacks.

addAction(action: str, func: Callable, *args, **kwargs)[source]

Adds a callback to the specified action.

All other positional and keyword arguments will be stored and passed to the function upon activation.

doAction(action: str)[source]

Helper method that calls all callbacks registered for the given action.

class peng3d.util.SmartRegistry(data: Optional[Dict[str, Any]] = None, reuse_ids: bool = False, start_id: int = 0, max_id: Optional[int] = None, default_reg: Optional[Dict[KT, VT]] = None)[source]

Smart registry allowing easy management of mappings from int to str and vice versa.

Note that bidict is required to be able to use this class.

data may be a dictionary to initialize the registry with. Only dictionaries gotten from the data property should be used.

reuse_ids specifies whether or not the automatic ID generator should re-use old, now unused IDs. See genNewID() for more information.

start_id is the lowest ID that will be generated by the automatic ID generator.

max_id is the highest ID that will be generated by the automatic ID generator. Should this limit by reached, an AssertionError will be raised.

default_reg may be a dictionary mapping IDs to names. It will only be used if data did not already contain a registry.

It is possible to access the registry via the dict-style reg[key] notation. This will return the name of whatever object was used as the key.

Registering is also possible in a similar manner, like reg[name]=id. id may be None to automatically generate one.

This class also supports the in operator, note that both IDs and names are checked.

data

Read-only property to access the internal data.

This is a dictionary containing all information necessary to re-create the registry via the data argument.

The returned object is fully JSON/YAML/MessagePack serializable, as it only contains basic python data types.

genNewID() → int[source]

Generates a new ID.

If reuse_ids was false, the new ID will be read from an internal counter which is also automatically increased. This means that the newly generated ID is already reserved.

If reuse_ids was true, this method starts counting up from start_id until it finds an ID that is not currently known. Note that the ID is not reserved, this means that calling this method simultaneously from multiple threads may cause the same ID to be returned twice.

Additionally, if the ID is greater or equal to max_id, an AssertionError is raised.

normalizeID(in_id: Union[int, str]) → int[source]

Takes in an object and normalizes it to its ID/integer representation.

Currently, only integers and strings may be passed in, else a TypeError will be thrown.

normalizeName(in_name: Union[int, str]) → str[source]

Takes in an object and normalizes it to its name/string.

Currently, only integers and strings may be passed in, else a TypeError will be thrown.

register(name: str, force_id: Optional[int] = None) → int[source]

Registers a name to the registry.

name is the name of the object and must be a string.

force_id can be optionally set to override the automatic ID generation and force a specific ID.

Note that using force_id is discouraged, since it may cause problems when reuse_ids is false.

peng3d.util.default(arg: Optional[T], _default: T) → T[source]

Small helper function that replaces the given argument with a default if the argument is None.

This can also be written as a ternary expression in-line, but using this function makes the purpose clearer and easier to read.

class peng3d.util.default_property(parent: Optional[str] = None, name: Optional[str] = None, *, parent_attr: Optional[str] = None)[source]

Special property decorator/class that allows for easy defaulting of attributes to the parents’ attributes.

This class can either be used as a decorator or as a class attribute.

For decorator usage, simply decorate an empty method with the name of the attribute to default, passing the name of the attribute the parent is stored in:

class A:
    @default_property("parent")
    def my_attr(self): ...

Accessing my_attr will then return the value of the my_attr attribute of the parent attribute of the class instance. Setting my_attr will not touch the attribute of the same name of the parent, but rather set an internal attribute, causing all subsequent accesses to return this local attribute.

Setting the property to None will reset the whole mechanism, causing all accesses until the next write to return the defaulted value.

Internally, all this is handled by a shadow attribute with the same name as the actual property, but prefixed by an underscore. This internal attribute may also be written to directly, which is especially useful in constructors.

Deleting the property will also just reset it, until it is next written.

Alternatively, this class can also be used as a class attribute, for the same effect as described above:

class A:
    my_attr = default_property("parent")

Note that this only works if the property is defined in the class body. Later assignment to the class object is possible, but requires providing the name argument, since auto-detecting the attribute name is then not possible.

To simplify creation, it is possible to set the PARENT_ATTR class attribute to provide a default first argument to default_property. This is usually worthwhile if multiple default_properties are used within the same class hierarchy, especially since the class attribute value can be inherited.

The parent_attr keyword-only argument may be passed to override what attribute of the parent is used as a default.