pg.Symbolic

Accessible via pg.Symbolic, pg.symbolic.Symbolic.

class Symbolic(*, allow_partial, accessor_writable, sealed, root_path, init_super=True)[source]

Bases: TopologyAware, pg.Formattable, pg.JSONConvertible, pg.MaybePartial, pg.views.HtmlConvertible

Base for all symbolic types.

Symbolic types are types that provide interfaces for symbolic programming, based on which symbolic objects can be created. In PyGlove, there are three categories of symbolic types:

Classes:

DictType

alias of pg.Dict

ListType

alias of pg.List

ObjectType

alias of pg.Object

Methods:

TYPE_CONVERTER()

Get converter from source type to a JSON simple type.

__copy__()

Overridden shallow copy.

__deepcopy__(memo)

Overridden deep copy.

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 into a string representation.

from_json(json_value, **kwargs)

Creates an instance of this class from a plain Python 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.

load_types_for_deserialization(...)

Context manager for loading unregistered types for deserialization.

missing_values([flatten])

Alias for sym_missing.

non_default_values([flatten])

Alias for sym_nondefault.

rebind([path_value_pairs, ...])

Alias for sym_rebind.

register(type_name, subclass[, ...])

Registers a class with a type name.

registered_types()

Returns an iterator of registered (serialization key, class) tuples.

save(*args, **kwargs)

Saves current object using the global save handler.

seal([sealed])

Alias for sym_seal.

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)

Returns if this object equals to another object symbolically.

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)

Returns if a symbolic attribute exists.

sym_hash()

Computes the symbolic hash of current object.

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.

sym_items()

Iterates the (key, value) pairs of symbolic attributes.

sym_jsonify(*[, hide_default_values])

Converts representation of current object to a plain Python object.

sym_keys()

Iterates the keys of symbolic attributes.

sym_lt(other)

Returns True if this object is symbolically less than other object.

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.

sym_values()

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:

accessor_writable

Returns True if mutation can be made by attribute assignment.

allow_partial

Returns True if partial binding is allowed.

is_abstract

Alias for sym_abstract.

is_deterministic

Returns if current object is deterministic.

is_partial

Alias for sym_partial.

is_pure_symbolic

Alias for sym_puresymbolic.

is_sealed

Alias for sym_sealed.

sym_abstract

Returns True if current value is abstract (partial or pure symbolic).

sym_field

Returns the symbolic field for current object.

sym_origin

Returns the symbolic origin of current object.

sym_parent

Returns the containing symbolic object.

sym_partial

Returns True if current value is partial.

sym_path

Returns the path of current object from the root of its symbolic tree.

sym_puresymbolic

Returns True if current value is or contains subnodes of PureSymbolic.

sym_root

Returns the root of the symbolic tree.

sym_sealed

Returns True if current object is sealed.

DictType[source]

alias of pg.Dict

ListType[source]

alias of pg.List

ObjectType[source]

alias of pg.Object

TYPE_CONVERTER()[source]

Get converter from source type to a JSON simple type.

Return type:

Optional[Callable[[Any], Any]]

__copy__()[source]

Overridden shallow copy.

Return type:

pg.Symbolic

__deepcopy__(memo)[source]

Overridden deep copy.

Return type:

pg.Symbolic

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:

None

property allow_partial: bool[source]

Returns True if partial binding is allowed.

classmethod class_from_typename(type_name)[source]

Gets the class for a registered type name.

Return type:

Optional[Type[pg.JSONConvertible]]

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:

pg.Symbolic

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.

abstract format(compact=False, verbose=True, root_indent=0, **kwargs)[source]

Formats this object into a string representation.

Return type:

str

Parameters:
  • compact – If True, this object will be formatted into a single line.

  • verbose – If True, this object will be formatted with verbosity. Subclasses should define verbosity on their own.

  • root_indent – The start indent level for this object if the output is a multi-line string.

  • **kwargs – Subclass specific keyword arguments.

Returns:

A string of formatted object.

classmethod from_json(json_value, **kwargs)[source]

Creates an instance of this class from a plain Python value.

NOTE(daiyip): pg.Symbolic overrides from_json class method.

Return type:

pg.JSONConvertible

Parameters:
  • json_value – JSON value type.

  • **kwargs – Keyword arguments as flags to control object creation.

Returns:

An instance of cls.

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:

None

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.

property is_abstract: bool[source]

Alias for sym_abstract.

property is_deterministic: bool[source]

Returns if current object is deterministic.

property is_partial: bool[source]

Alias for sym_partial.

property is_pure_symbolic: bool[source]

Alias for sym_puresymbolic.

classmethod is_registered(type_name)[source]

Returns True if a type name is registered. Otherwise False.

Return type:

bool

property is_sealed: bool[source]

Alias for sym_sealed.

classmethod load(*args, **kwargs)[source]

Loads an instance of this type using the global load handler.

Return type:

Any

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.

missing_values(flatten=True)[source]

Alias for sym_missing.

Return type:

Dict[Union[str, int], Any]

non_default_values(flatten=True)[source]

Alias for sym_nondefault.

Return type:

Dict[Union[str, int], Any]

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.Symbolic

  • It 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 ValueError when 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_change event triggered from current rebind. If None, the default value will be inferred from the pg.notify_on_change context manager. Use it only when you are certain that current rebind does not invalidate internal states of its object tree.

  • **kwargs – For pg.Dict and pg.Object subclasses, 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:

None

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:

Iterable[Tuple[str, Type[pg.JSONConvertible]]]

save(*args, **kwargs)[source]

Saves current object using the global save handler.

Return type:

Any

seal(sealed=True)[source]

Alias for sym_seal.

Return type:

pg.Symbolic

set_accessor_writable(writable=True)[source]

Sets accessor writable.

Return type:

pg.Symbolic

property sym_abstract: bool[source]

Returns True if current value is abstract (partial or pure symbolic).

sym_ancestor(where=None)[source]

Returns the nearest ancestor of specific classes.

Return type:

Optional[pg.Symbolic]

abstract sym_attr_field(key)[source]

Returns the field definition for a symbolic attribute.

Return type:

Optional[pg.Field]

sym_clone(deep=False, memo=None, override=None)[source]

Clones current object symbolically.

sym_contains(value=None, type=None)[source]

Returns True if the object contains sub-nodes of given value or type.

Return type:

bool

sym_descendants(where=None, option=DescendantQueryOption.ALL, include_self=False)[source]

Returns all descendants of specific classes.

Return type:

List[Any]

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_eq(other)[source]

Returns if this object equals to another object symbolically.

Return type:

bool

property sym_field: Field | None[source]

Returns the symbolic field for current object.

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:

Any

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:

Any

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:

bool

sym_has(path)[source]

Returns True if a path exists in the sub-tree.

Return type:

bool

Parameters:

path – A KeyPath object or equivalence.

Returns:

True if the path exists in current sub-tree, otherwise False.

abstract sym_hasattr(key)[source]

Returns if a symbolic attribute exists.

Return type:

bool

abstract sym_hash()[source]

Computes the symbolic hash of current object.

Return type:

int

sym_inferrable(key, **kwargs)[source]

Returns True if the attribute under key can be inferred.

Return type:

bool

sym_inferred(key, default=(MISSING_VALUE,), **kwargs)[source]

Returns the inferred value of the attribute under key.

Return type:

Any

abstract sym_items()[source]

Iterates the (key, value) pairs of symbolic attributes.

Return type:

Iterator[Tuple[Union[str, int], Any]]

abstract sym_jsonify(*, hide_default_values=False, **kwargs)[source]

Converts representation of current object to a plain Python object.

Return type:

Union[int, float, bool, str, List[Any], Dict[Union[str, int], Any]]

abstract sym_keys()[source]

Iterates the keys of symbolic attributes.

Return type:

Iterator[Union[str, int]]

sym_lt(other)[source]

Returns True if this object is symbolically less than other object.

Return type:

bool

sym_missing(flatten=True)[source]

Returns missing values.

Return type:

Dict[Union[str, int], Any]

sym_ne(other)[source]

Returns if this object does not equal to another object symbolically.

Return type:

bool

sym_nondefault(flatten=True)[source]

Returns missing values.

Return type:

Dict[Union[str, int], Any]

property sym_origin: Origin | None[source]

Returns the symbolic origin of current object.

property sym_parent: Symbolic[source]

Returns the containing symbolic object.

property sym_partial: bool[source]

Returns True if current value is partial.

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:

pg.Symbolic

property sym_root: Symbolic[source]

Returns the root of the symbolic tree.

sym_seal(is_seal=True)[source]

Seals or unseals current object from further modification.

Return type:

pg.Symbolic

property sym_sealed: bool[source]

Returns True if current object is sealed.

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 inside sym_setorigin.

sym_setparent(parent)[source]

Sets the parent of current node in the symbolic tree.

sym_setpath(path)[source]

Sets the path of current node in its symbolic tree.

Return type:

None

abstract sym_values()[source]

Iterates the values of symbolic attributes.

Return type:

Iterator[Any]

to_html(**kwargs)[source]

Returns the HTML representation of the object.

Return type:

pg.Html

to_html_str(*, content_only=False, **kwargs)[source]

Returns the HTML str of the object.

Return type:

str

to_json(**kwargs)[source]

Alias for sym_jsonify.

Return type:

Union[int, float, bool, str, List[Any], Dict[Union[str, int], Any]]

classmethod to_json_dict(fields, *, exclude_default=False, exclude_keys=None, **kwargs)[source]

Helper method to create JSON dict from class and field.

Return type:

Dict[str, Union[int, float, bool, str, List[Any], Dict[Union[str, int], Any]]]

to_json_str(json_indent=None, **kwargs)[source]

Serializes current object into a JSON string.

Return type:

str