extensible_storage
Generic Extensible Storage helper.
Extensible Storage lets a tool attach small bits of typed data to any Element and have Revit persist it as part of the model. Used directly, that means writing SchemaBuilder/Entity boilerplate -- a GUID, field types, access levels, generic Get[T]/Set[T] calls -- every time a tool needs to remember something about an element. This module wraps that boilerplate behind two things:
* BaseSchema -- a plain class a tool subclasses to *declare* its
schema (GUID, name, vendor id, fields) instead of building one
by hand.
* ElementDataStorage -- reads/writes/clears an element's Entity for
a given schema as a plain dict, so callers never touch
SchemaBuilder, Entity, or Get[T]/Set[T] directly.
Only "simple" fields (a single value per field -- str, int, float, bool, DB.ElementId, System.Guid, etc.) and "array" fields (an ordered list of one of those types -- e.g. every ElementId a tool generated) are covered directly. A schema that also needs SchemaBuilder.AddMapField can add it via the BaseSchema.extend_builder hook (see below).
Example:
from pyrevit import DB
from pyrevit.coreutils import extensible_storage
class MyToolLinkSchema(extensible_storage.BaseSchema):
guid = "a1b2c3d4-e5f6-4a7b-8c9d-0123456789ab"
schema_name = "MyToolElementLink"
vendor_id = "mytool"
fields = {"LinkedId": DB.ElementId}
storage = extensible_storage.ElementDataStorage(MyToolLinkSchema)
with revit.Transaction("Link elements"):
storage.set_data(some_element, LinkedId=other_element.Id)
data = storage.get_data(some_element)
if data:
linked_id = data["LinkedId"]
# A list-valued field works the same way, just declared under
# array_fields instead of fields:
class MyToolManagedElementsSchema(extensible_storage.BaseSchema):
guid = "a1b2c3d4-e5f6-4a7b-8c9d-0123456789ab"
schema_name = "MyToolManagedElements"
vendor_id = "mytool"
array_fields = {"ManagedIds": DB.ElementId}
managed = extensible_storage.ElementDataStorage(MyToolManagedElementsSchema)
managed.set_data(some_view, ManagedIds=[a.Id, b.Id, c.Id])
data = managed.get_data(some_view)
if data:
ids = data["ManagedIds"] # list of ElementId
Classes
BaseSchema
Bases: object
Subclass to declaratively define an Extensible Storage schema.
Class attributes
guid (str): fixed schema GUID as a string. Generate a fresh
one per schema and never change it once the schema is in use)
schema_name (str): schema name (letters/digits/underscore,
must start with a letter)
vendor_id (str): short vendor/application id required by
SchemaBuilder.SetVendorId -- any short alphanumeric string
is accepted, Revit does not validate it against a registry
application_guid (str or None): optional -- only needed to
further scope AccessLevel.Application/Vendor reads
read_access_level / write_access_level
(DB.ExtensibleStorage.AccessLevel): default Public
(readable/writable by any application, not just the one
that wrote it)
fields (dict): {field_name: field_type}, e.g.
{"LinkedId": DB.ElementId, "Note": str}. Only simple
(single-value) fields.
array_fields (dict): {field_name: element_type}, e.g.
{"ManagedIds": DB.ElementId} -- each is stored/read as an
ordered list of that type. A field name must not appear in
both fields and array_fields.
documentation (str or None): optional overall schema doc string
Attributes
guid = None
class-attribute
instance-attribute
schema_name = None
class-attribute
instance-attribute
vendor_id = 'pyrvt'
class-attribute
instance-attribute
application_guid = None
class-attribute
instance-attribute
read_access_level = DB.ExtensibleStorage.AccessLevel.Public
class-attribute
instance-attribute
write_access_level = DB.ExtensibleStorage.AccessLevel.Public
class-attribute
instance-attribute
fields = {}
class-attribute
instance-attribute
array_fields = {}
class-attribute
instance-attribute
documentation = None
class-attribute
instance-attribute
Methods:
extend_builder(builder)
classmethod
Override to add anything SchemaBuilder supports beyond simple and array fields -- i.e. builder.AddMapField(...) -- before the schema is finished. Called once, right before Finish(), only when the schema is being newly registered. No-op by default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
builder
|
DB.ExtensibleStorage.SchemaBuilder being built |
required |
Source code in pyrevitlib/pyrevit/coreutils/extensible_storage.py
ElementDataStorage(schema_cls)
Bases: object
Reads/writes/clears one element's Entity for a given
BaseSchema subclass, as a plain dict of field name -> value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema_cls
|
a BaseSchema subclass describing the schema to read/write |
required |
Source code in pyrevitlib/pyrevit/coreutils/extensible_storage.py
Attributes
schema
property
DB.ExtensibleStorage.Schema: the registered schema, built and registered on first access if not already present in this document/session.
Methods:
has_data(element)
bool: whether element currently has an Entity for this
schema.
Source code in pyrevitlib/pyrevit/coreutils/extensible_storage.py
get_data(element)
Read this schema's data off element.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
element
|
DB.Element to read from |
required |
Returns:
| Name | Type | Description |
|---|---|---|
dict |
{field_name: value} for every field declared on the
schema (default-valued for any field never explicitly
set), or None if |
Source code in pyrevitlib/pyrevit/coreutils/extensible_storage.py
set_data(element, **field_values)
Write (or overwrite) this schema's Entity on element.
This replaces the whole Entity, not just the fields passed -- any declared field you don't pass reverts to its CLR default (0 / empty string / InvalidElementId, depending on type) rather than keeping whatever was there before. Pass every field you care about each time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
element
|
DB.Element to write to |
required | |
**field_values
|
value for each field name declared in the
schema's |
{}
|
Must be called inside an open transaction.
Source code in pyrevitlib/pyrevit/coreutils/extensible_storage.py
clear_data(element)
Remove this schema's Entity from element, if present.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
element
|
DB.Element to clear |
required |
Must be called inside an open transaction.