pg.Object¶
Accessible via pg.Object, pg.symbolic.Object.
- class Object(*args, allow_partial=False, sealed=None, root_path=None, explicit_init=False, **kwargs)[source]¶
Bases:
pg.SymbolicBase class for symbolic user classes.
PyGlove allow symbolic programming interfaces to be easily added to most Python classes in two ways:
Developing a dataclass-like symbolic class by subclassing
pg.Object.Developing a class as usual and decorate it using
pg.symbolize. This also work with existing classes.
By directly subclassing
pg.Object, programmers can create new symbolic classes with the least effort. For example:@pg.members([ # Each tuple in the list defines a symbolic field for `__init__`. ('name', pg.typing.Str().noneable(), 'Name to greet'), ('time_of_day', pg.typing.Enum('morning', ['morning', 'afternnon', 'evening']), 'Time of the day.') ]) class Greeting(pg.Object): def __call__(self): # Values for symbolic fields can be accessed # as public data members of the symbolic object. print(f'Good {self.time_of_day}, {self.name}') # Create an object of Greeting and invoke it, # which shall print 'Good morning, Bob'. Greeting('Bob')()
Symbolic fields can be inherited from the base symbolic class: the fields from the base class will be copied to the subclass in their declaration order, while the subclass can override the inherited fields with more restricted validation rules or different default values. For example:
@pg.members([ ('x', pg.typing.Int(max_value=10)), ('y', pg.typing.Float(min_value=0)) ]) class Foo(pg.Object) pass @pg.members([ ('x', pg.typing.Int(min_value=1, default=1)), ('z', pg.typing.Str().noneable()) ]) class Bar(Foo) pass # Printing Bar's schema will show that there are 3 parameters defined: # x : pg.typing.Int(min_value=1, max_value=10, default=1)) # y : pg.typing.Float(min_value=0) # z : pg.typing.Str().noneable() print(Bar.__schema__)
Classes:
Methods:
Get converter from source type to a JSON simple type.
__copy__()Overridden shallow copy.
__deepcopy__(memo)Overridden deep copy.
__eq__(other)Operator==.
__hash__()Hashing function.
__ne__(other)Operator!=.
Event that is triggered when any value in the subtree are set/updated.
_on_change(field_updates)Event that is triggered when field values in the subtree are updated.
_on_init()Event that is triggered at then end of __init__.
_on_parent_change(old_parent, new_parent)Event that is triggered after the symbolic parent changes.
_on_path_change(old_path, new_path)Event that is triggered after the symbolic path changes.
add_module_alias(module, alias)Adds a module alias so previous serialized objects could be loaded.
class_from_typename(type_name)Gets the class for a registered type name.
clone([deep, memo, override])Clones current object symbolically.
format([compact, verbose, root_indent])Formats this object.
from_json(json_value, *[, allow_partial, ...])Class method that load an symbolic Object from a JSON value.
inspect([path_regex, where, ...])Inspects current object by printing out selected values.
is_registered(type_name)Returns True if a type name is registered.
load(*args, **kwargs)Loads an instance of this type using the global load handler.
Context manager for loading unregistered types for deserialization.
missing_values([flatten])Alias for sym_missing.
non_default_values([flatten])Alias for sym_nondefault.
partial(*args, **kwargs)Class method that creates a partial object of current class.
rebind([path_value_pairs, ...])Alias for sym_rebind.
register(type_name, subclass[, ...])Registers a class with a type name.
Returns an iterator of registered (serialization key, class) tuples.
save(*args, **kwargs)Saves current object using the global save handler.
seal([sealed])Seal or unseal current object from further modification.
set_accessor_writable([writable])Sets accessor writable.
sym_ancestor([where])Returns the nearest ancestor of specific classes.
sym_attr_field(key)Returns the field definition for a symbolic attribute.
sym_clone([deep, memo, override])Clones current object symbolically.
sym_contains([value, type])Returns True if the object contains sub-nodes of given value or type.
sym_descendants([where, option, include_self])Returns all descendants of specific classes.
sym_eq(other)Tests symbolic equality.
sym_get(path[, default, use_inferred])Returns a sub-node by path.
sym_getattr(key[, default])Gets a symbolic attribute.
sym_gt(other)Returns if this object is symbolically greater than another object.
sym_has(path)Returns True if a path exists in the sub-tree.
sym_hasattr(key)Tests if a symbolic attribute exists.
sym_hash()Symbolically hashing.
sym_inferrable(key, **kwargs)Returns True if the attribute under key can be inferred.
sym_inferred(key[, default])Returns the inferred value of the attribute under key.
Iterates the (key, value) pairs of symbolic attributes.
sym_jsonify(**kwargs)Converts current object to a dict of plain Python objects.
sym_keys()Iterates the keys of symbolic attributes.
sym_lt(other)Tests symbolic less-than.
sym_missing([flatten])Returns missing values.
sym_ne(other)Returns if this object does not equal to another object symbolically.
sym_nondefault([flatten])Returns missing values.
sym_rebind([path_value_pairs, ...])Mutates the sub-nodes of current object.
sym_seal([is_seal])Seals or unseals current object from further modification.
sym_setorigin(source, tag[, stacktrace, ...])Sets the symbolic origin of current object.
sym_setparent(parent)Sets the parent of current node in the symbolic tree.
sym_setpath(path)Sets the path of current node in its symbolic tree.
Iterates the values of symbolic attributes.
to_html(**kwargs)Returns the HTML representation of the object.
to_html_str(*[, content_only])Returns the HTML str of the object.
to_json(**kwargs)Alias for sym_jsonify.
to_json_dict(fields, *[, exclude_default, ...])Helper method to create JSON dict from class and field.
to_json_str([json_indent])Serializes current object into a JSON string.
Attributes:
Returns True if mutation can be made by attribute assignment.
Returns True if partial binding is allowed.
Alias for sym_abstract.
Returns if current object is deterministic.
Alias for sym_partial.
Alias for sym_puresymbolic.
Alias for sym_sealed.
Returns True if current value is abstract (partial or pure symbolic).
Returns the symbolic field for current object.
Returns the symbolic attributes which are also the __init__ args.
Returns the symbolic origin of current object.
Returns the containing symbolic object.
Returns True if current value is partial.
Returns the path of current object from the root of its symbolic tree.
Returns True if current value is or contains subnodes of PureSymbolic.
Returns the root of the symbolic tree.
Returns True if current object is sealed.
- _on_bound()[source]¶
Event that is triggered when any value in the subtree are set/updated.
NOTE(daiyip): This is the best place to set derived members from members registered by the schema. It’s called when any value in the sub-tree is modified, thus making sure derived members are up-to-date.
When derived members are expensive to create/update, you can implement _init, _on_rebound, _on_subtree_rebound to update derived members only when they are impacted.
_on_bound is not called on per-field basis, it’s called at most once during a rebind call (though many fields may be updated) and during __init__.
- Return type:
- _on_change(field_updates)[source]¶
Event that is triggered when field values in the subtree are updated.
- This event will be called
On per-field basis when object is modified via attribute.
In batch when multiple fields are modified via rebind method.
When a field in an object tree is updated, all ancestors’ _on_change event will be triggered in order, from the nearest one to furthest one.
- Parameters:
field_updates – Updates made to the subtree. Key path is relative to current object.
- Returns:
it will call _on_bound and return the return value of _on_bound.
- _on_parent_change(old_parent, new_parent)[source]¶
Event that is triggered after the symbolic parent changes.
- _on_path_change(old_path, new_path)[source]¶
Event that is triggered after the symbolic path changes.
- property accessor_writable: bool[source]¶
Returns True if mutation can be made by attribute assignment.
- classmethod add_module_alias(module, alias)[source]¶
Adds a module alias so previous serialized objects could be loaded.
- Return type:
- classmethod class_from_typename(type_name)[source]¶
Gets the class for a registered type name.
- Return type:
- Parameters:
type_name – A string as the global unique type identifier for requested class.
- Returns:
A type object if registered, otherwise None.
- clone(deep=False, memo=None, override=None)[source]¶
Clones current object symbolically.
- Return type:
- Parameters:
deep – If True, perform deep copy (equivalent to copy.deepcopy). Otherwise shallow copy (equivalent to copy.copy).
memo – Memo object for deep clone.
override – An optional dict of key path to new values to override cloned value.
- Returns:
A copy of self.
- format(compact=False, verbose=False, root_indent=0, **kwargs)[source]¶
Formats this object.
- Return type:
- classmethod from_json(json_value, *, allow_partial=False, root_path=None, **kwargs)[source]¶
Class method that load an symbolic Object from a JSON value.
Example:
@pg.members([ ('f1', pg.typing.Int()), ('f2', pg.typing.Dict([ ('f21', pg.typing.Bool()) ])) ]) class Foo(pg.Object): pass foo = Foo.from_json({ 'f1': 1, 'f2': { 'f21': True } }) # or foo2 = symbolic.from_json({ '_type': '__main__.Foo', 'f1': 1, 'f2': { 'f21': True } }) assert foo == foo2
- Return type:
- Parameters:
json_value – Input JSON value, only JSON dict is acceptable.
allow_partial – Whether to allow elements of the list to be partial.
root_path – KeyPath of loaded object in its object tree.
**kwargs – Additional keyword arguments to pass through.
- Returns:
A symbolic Object instance.
- inspect(path_regex=None, where=None, custom_selector=None, file=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>, **kwargs)[source]¶
Inspects current object by printing out selected values.
Example:
@pg.members([ ('x', pg.typing.Int(0)), ('y', pg.typing.Str()) ]) class A(pg.Object): pass value = { 'a1': A(x=0, y=0), 'a2': [A(x=1, y=1), A(x=1, y=2)], 'a3': { 'p': A(x=2, y=1), 'q': A(x=2, y=2) } } # Inspect without constraint, # which is equivalent as `print(value.format(hide_default_values=True))` # Shall print: # { # a1 = A(y=0) # a2 = [ # 0: A(x=1, y=1) # 1: A(x=1, y=2) # a3 = { # p = A(x=2, y=1) # q = A(x=2, y=2) # } # } value.inspect(hide_default_values=True) # Inspect by path regex. # Shall print: # {'a3.p': A(x=2, y=1)} value.inspect(r'.*p') # Inspect by value. # Shall print: # { # 'a3.p.x': 2, # 'a3.q.x': 2, # 'a3.q.y': 2, # } value.inspect(where=lambda v: v==2) # Inspect by path, value and parent. # Shall print: # { # 'a2[1].y': 2 # } value.inspect( r'.*y', where=lambda v, p: v > 1 and isinstance(p, A) and p.x == 1)) # Inspect by custom_selector. # Shall print: # { # 'a2[0].x': 1, # 'a2[0].y': 1, # 'a3.q.x': 2, # 'a3.q.y': 2 # } value.inspect( custom_selector=lambda k, v, p: ( len(k) == 3 and isinstance(p, A) and p.x == v))
- Return type:
- Parameters:
path_regex – Optional regex expression to constrain path.
where – Optional callable to constrain value and parent when path matches path_regex or path_regex is not provided. The signature is: (value) -> should_select, or (value, parent) -> should_select.
custom_selector – Optional callable object as custom selector. When custom_selector is provided, path_regex and where must be None. The signature of custom_selector is: (key_path, value) -> should_select or (key_path, value, parent) -> should_select.
file – Output file stream. This can be any object with a write(str) method.
**kwargs – Wildcard keyword arguments to pass to format.
- classmethod is_registered(type_name)[source]¶
Returns True if a type name is registered. Otherwise False.
- Return type:
- classmethod load(*args, **kwargs)[source]¶
Loads an instance of this type using the global load handler.
- Return type:
- classmethod load_types_for_deserialization(*types_to_deserialize)[source]¶
Context manager for loading unregistered types for deserialization.
Example:
class A(pg.Object): auto_register = False x: int class B(A): y: str with pg.JSONConvertile.load_types_for_deserialization(A, B): pg.from_json_str(A(1).to_json_str()) pg.from_json_str(B(1, 'hi').to_json_str())
- Return type:
ContextManager[Dict[str,Type[Any]]]- Parameters:
*types_to_deserialize – A list of types to be loaded for deserialization.
- Returns:
- A context manager within which the objects of the requested types
could be deserialized.
- classmethod partial(*args, **kwargs)[source]¶
Class method that creates a partial object of current class.
- Return type:
- rebind(path_value_pairs=None, *, raise_on_no_change=True, notify_parents=True, skip_notification=None, **kwargs)[source]¶
Alias for sym_rebind.
Alias for sym_rebind. rebind is the recommended way for mutating symbolic objects in PyGlove: :rtype:
pg.SymbolicIt allows mutations not only on immediate child nodes, but on the entire sub-tree.
It allows mutations by rules via passing a callable object as the value for path_value_pairs.
It batches the updates from multiple sub-nodes, which triggers the _on_change or _on_bound event once for recomputing the parent object’s internal states.
It respects the “sealed” flag of the object or the pg.seal context manager to trigger permission error.
Example:
# # Rebind on pg.Object subclasses. # @pg.members([ ('x', pg.typing.Dict([ ('y', pg.typing.Int(default=0)) ])), ('z', pg.typing.Int(default=1)) ]) class A(pg.Object): pass a = A() # Rebind using path-value pairs. a.rebind({ 'x.y': 1, 'z': 0 }) # Rebind using **kwargs. a.rebind(x={y: 1}, z=0) # Rebind using rebinders. # Rebind based on path. a.rebind(lambda k, v: 1 if k == 'x.y' else v) # Rebind based on key. a.rebind(lambda k, v: 1 if k and k.key == 'y' else v) # Rebind based on value. a.rebind(lambda k, v: 0 if v == 1 else v) # Rebind baesd on value and parent. a.rebind(lambda k, v, p: (0 if isinstance(p, A) and isinstance(v, int) else v)) # Rebind on pg.Dict. # d = pg.Dict(value_spec=pg.typing.Dict([ ('a', pg.typing.Dict([ ('b', pg.typing.Int()), ])), ('c', pg.typing.Float()) ]) # Rebind using **kwargs. d.rebind(a={b: 1}, c=1.0) # Rebind using key path to value dict. d.rebind({ 'a.b': 2, 'c': 2.0 }) # NOT OKAY: **kwargs and dict/rebinder cannot be used at the same time. d.rebind({'a.b': 2}, c=2) # Rebind with rebinder by path (on subtree). d.rebind(lambda k, v: 1 if k.key == 'b' else v) # Rebind with rebinder by value (on subtree). d.rebind(lambda k, v: 0 if isinstance(v, int) else v) # # Rebind on pg.List. # l = pg.List([{ 'a': 'foo', 'b': 0, } ], value_spec = pg.typing.List(pg.typing.Dict([ ('a', pg.typing.Str()), ('b', pg.typing.Int()) ]), max_size=10)) # Rebind using integer as list index: update semantics on list[0]. l.rebind({ 0: { 'a': 'bar', 'b': 1 } }) # Rebind: trigger append semantics when index is larger than list length. l.rebind({ 999: { 'a': 'fun', 'b': 2 } }) # Rebind using key path. l.rebind({ '[0].a': 'bar2' '[1].b': 3 }) # Rebind using function (rebinder). # Change all integers to 0 in sub-tree. l.rebind(lambda k, v: v if not isinstance(v, int) else 0)
- Parameters:
path_value_pairs –
A dictionary of key/or key path to new field value, or a function that generate updates based on the key path, value and parent of each node under current object. We use terminology ‘rebinder’ for this type of functions. The signature of a rebinder is:
(key_path: pg.KeyPath, value: Any) or (key_path: pg.KeyPath, value: Any, parent: pg.Symbolic)
raise_on_no_change – If True, raises
ValueErrorwhen there are no values to change. This is useful when rebinder is used, which may or may not generate any updates.notify_parents – If True (default), parents will be notified upon change. Otherwisee only the current object and the impacted children will be notified. A most common use case for setting this flag to False is when users want to rebind a child within the parent _on_bound method.
skip_notification – If True, there will be no
_on_changeevent triggered from current rebind. If None, the default value will be inferred from thepg.notify_on_changecontext manager. Use it only when you are certain that current rebind does not invalidate internal states of its object tree.**kwargs – For
pg.Dictandpg.Objectsubclasses, user can use keyword arguments (in format of <field_name>=<field_value>) to directly modify immediate child nodes.
- Returns:
Self.
- Raises:
WritePermissionError – If object is sealed.
KeyError – If update location specified by key or key path is not aligned with the schema of the object tree.
TypeError – If updated field value type does not conform to field spec.
ValueError – If updated field value is not acceptable according to field spec, or nothing is updated and raise_on_no_change is set to True.
- classmethod register(type_name, subclass, override_existing=False)[source]¶
Registers a class with a type name.
The type name will be used as the key for class lookup during deserialization. A class can be registered with multiple type names, but a type name should be uesd only for one class.
- Return type:
- Parameters:
type_name – A global unique string identifier for subclass.
subclass – A subclass of JSONConvertible.
override_existing – If True, override the class if the type name is already present in the registry. Otherwise an error will be raised.
- classmethod registered_types()[source]¶
Returns an iterator of registered (serialization key, class) tuples.
- Return type:
- property sym_abstract: bool[source]¶
Returns True if current value is abstract (partial or pure symbolic).
- sym_contains(value=None, type=None)[source]¶
Returns True if the object contains sub-nodes of given value or type.
- Return type:
- sym_descendants(where=None, option=DescendantQueryOption.ALL, include_self=False)[source]¶
Returns all descendants of specific classes.
- Return type:
- Parameters:
where – Optional callable object as the filter of descendants to return.
option – Descendant query options, indicating whether all matched, immediate matched or only the matched leaf nodes will be returned.
include_self – If True, self will be included in the query, otherwise only strict descendants are included.
- Returns:
A list of objects that match the descendant_cls.
- sym_get(path, default=(MISSING_VALUE,), use_inferred=False)[source]¶
Returns a sub-node by path.
NOTE: there is no sym_set, use sym_rebind.
- Return type:
- Parameters:
path – A KeyPath object or equivalence.
default – Default value if path does not exists. If absent, KeyError will be thrown.
use_inferred – If True, return inferred value instead of the symbolic form of pg.Inferential objects.
- Returns:
Value of symbolic attribute specified by path if found, otherwise the default value if it’s specified.
- Raises:
KeyError if path does not exist and default is not specified. –
- sym_getattr(key, default=(MISSING_VALUE,))[source]¶
Gets a symbolic attribute.
- Return type:
- Parameters:
key – Key of symbolic attribute.
default – Default value if attribute does not exist. If absent,
- Returns:
Value of symbolic attribute if found, otherwise the default value if it’s specified.
- Raises:
AttributeError if key does not exist and default is not provided. –
- sym_gt(other)[source]¶
Returns if this object is symbolically greater than another object.
- Return type:
- sym_has(path)[source]¶
Returns True if a path exists in the sub-tree.
- Return type:
- Parameters:
path – A KeyPath object or equivalence.
- Returns:
True if the path exists in current sub-tree, otherwise False.
- sym_inferrable(key, **kwargs)[source]¶
Returns True if the attribute under key can be inferred.
- Return type:
- sym_inferred(key, default=(MISSING_VALUE,), **kwargs)[source]¶
Returns the inferred value of the attribute under key.
- Return type:
- property sym_init_args: Dict[source]¶
Returns the symbolic attributes which are also the __init__ args.
- Returns:
- A symbolic Dict as evaluated symbolic attributes, meaning that all
pg.ContextValuewill be resolved.
- sym_ne(other)[source]¶
Returns if this object does not equal to another object symbolically.
- Return type:
- property sym_path: KeyPath[source]¶
Returns the path of current object from the root of its symbolic tree.
- property sym_puresymbolic: bool[source]¶
Returns True if current value is or contains subnodes of PureSymbolic.
- sym_rebind(path_value_pairs=None, *, raise_on_no_change=True, notify_parents=True, skip_notification=None, **kwargs)[source]¶
Mutates the sub-nodes of current object. Please see rebind.
- Return type:
- sym_seal(is_seal=True)[source]¶
Seals or unseals current object from further modification.
- Return type:
- sym_setorigin(source, tag, stacktrace=None, stacklimit=None, stacktop=-1)[source]¶
Sets the symbolic origin of current object.
- Parameters:
source – Source value for current object.
tag – A descriptive tag of the origin. Built-in tags are: __init__, clone, deepclone, return. Users can manually call sym_setorigin with custom tag value.
stacktrace – If True, enable stack trace for the origin. If None, enable stack trace if pg.tracek_origin() is called. Otherwise stack trace is disabled.
stacklimit – An optional integer to limit the stack depth. If None, it’s determined by the value passed to pg.set_origin_stacktrace_limit, which is 10 by default.
stacktop – A negative or zero-value integer indicating the stack top among the stack frames that we want to present to user, by default it’s 1-level up from the stack within current sym_setorigin call.
Example:
def foo(): return bar() def bar(): s = MyObject() t = s.build() t.sym_setorigin(s, 'builder', stacktrace=True, stacklimit=5, stacktop=-1)
This example sets the origin of t using s as its source with tag ‘builder’. We also record the callstack where the sym_setorigin is called, so users can call t.sym_origin.stacktrace to get the call stack later. The stacktop -1 indicates that we do not need the stack frame within
sym_setorigin, so users will see the stack top within the function bar. We also set the max number of stack frames to display to 5, not including the stack frame insidesym_setorigin.
- to_html_str(*, content_only=False, **kwargs)[source]¶
Returns the HTML str of the object.
- Return type: