mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
|
from six.moves import reprlib
|
||
|
|
||
|
import records
|
||
|
|
||
|
|
||
|
class AttributeRecorder(object):
|
||
|
"""
|
||
|
Wrapper around a Record that records attribute accesses.
|
||
|
Used to generate a prompt for the AI with basic 'debugging' info.
|
||
|
"""
|
||
|
def __init__(self, inner, name, attributes):
|
||
|
assert isinstance(inner, records.Record)
|
||
|
self._inner = inner
|
||
|
self._name = name
|
||
|
self._attributes = attributes
|
||
|
|
||
|
def __getattr__(self, name):
|
||
|
"""
|
||
|
Record attribute access.
|
||
|
If the result is a Record or RecordSet, wrap that with AttributeRecorder
|
||
|
to also record nested attribute values.
|
||
|
"""
|
||
|
result = getattr(self._inner, name)
|
||
|
full_name = "{}.{}".format(self._name, name)
|
||
|
if isinstance(result, records.Record):
|
||
|
result = AttributeRecorder(result, full_name, self._attributes)
|
||
|
elif isinstance(result, records.RecordSet):
|
||
|
# Use a tuple to imply immutability so that the AI doesn't try appending.
|
||
|
# Don't try recording attributes of all contained records, just record the first access.
|
||
|
# Pretend that the attribute is always accessed from the first record for simplicity.
|
||
|
result = tuple(AttributeRecorder(r, full_name + "[0]", self._attributes) for r in result)
|
||
|
self._attributes.setdefault(full_name, safe_repr(result))
|
||
|
return result
|
||
|
|
||
|
def __repr__(self):
|
||
|
# The usual Record repr looks like Table1[2] which may surprise the AI.
|
||
|
return "{}(id={})".format(self._inner._table.table_id, self._inner._row_id)
|
||
|
|
||
|
|
||
|
arepr = reprlib.Repr()
|
||
|
arepr.maxlevel = 3
|
||
|
arepr.maxtuple = 3
|
||
|
arepr.maxlist = 3
|
||
|
arepr.maxarray = 3
|
||
|
arepr.maxdict = 4
|
||
|
arepr.maxset = 3
|
||
|
arepr.maxfrozenset = 3
|
||
|
arepr.maxdeque = 3
|
||
|
arepr.maxstring = 40
|
||
|
arepr.maxlong = 20
|
||
|
arepr.maxother = 60
|
||
|
|
||
|
|
||
|
def safe_repr(x):
|
||
|
try:
|
||
|
return arepr.repr(x)
|
||
|
except Exception:
|
||
|
# Copied from Repr.repr_instance in Python 3.
|
||
|
return '<%s instance at %#x>' % (x.__class__.__name__, id(x))
|