Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{pyactr} Change PrintBuffer to remove remaining monkey patching #381

Merged
merged 1 commit into from
Aug 15, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 82 additions & 36 deletions framework/pyactr/pyactr_print.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,25 @@
!goal>
show start

pyactr_print adds the ability to print strings, numbers, and slots (by name) from
multiple buffers by patching Buffer. It uses a new buffer called "print" with a
command "text" which takes a string:
pyactr_print adds the ability to print strings, numbers, buffer contents, and slots (by name)
from multiple buffers. It uses a new buffer called "print" with commands "text" and "buffer":

!print>
text "'Start is ', goal.start, ' and second is ', 'retrieval.second'"
buffer goal
buffer retrieval.word

This works by using fields from ACTRModel (reads & modifies "__buffers") and
Buffer (reads "_data") directly since there are no accessors for them.

Unfortunately due to the way pyactr is implemented, we are currently limited to
one print command per production. It does, however, allow multiple "text"s in
one print command per production. It does, however, allow multiple "text"s in
one command:

!print>
text "'a string'"
text "42"


To use this new buffer, construct it passing in the model like this:

import pyactr_print
Expand All @@ -39,27 +42,6 @@
from pyactr.buffers import Buffer


def get_slot_contents(self, buffer_name: str, slot_name: str) -> str:
"""
Gets the contents of a slot.
"""
if self._data:
chunk = self._data.copy().pop()
else:
chunk = None

try:
return str(getattr(chunk, slot_name))
except AttributeError:
print('ERROR: no slot named \'' + slot_name +
'\' in buffer \'' + buffer_name + '\'')
raise


# Monkey patch Buffer to add a new method.
Buffer.get_slot_contents = get_slot_contents


class PrintBuffer(actr.buffers.Buffer):
def __init__(self, model: actr.ACTRModel):
actr.buffers.Buffer.__init__(self, None, None)
Expand All @@ -68,7 +50,15 @@ def __init__(self, model: actr.ACTRModel):

def text(self, *args):
"""
Prints the args - including strings, numbers, and slots (by name).
Provides the "text" command.
Prints the args - including strings, numbers, buffer contents, and slots (by name).

Examples:
!print>
text "'Start is ', goal.start, ' and second is ', 'retrieval.second'"
text "'retrieval contents: ', retrieval"
text "'a string'"
text "42"
"""
text = ''.join(args[1:]).strip('"')
output = '' # build up our output in this buffer
Expand All @@ -86,18 +76,74 @@ def text(self, *args):
float(item)
output += item
except ValueError:
# If we are here, we should have a buffer.slotname
ids = item.split('.')
if len(ids) != 2:
print(
'ERROR: expected <buffer>.<slot_name>, found \'' +
item + '\'')
else:
buffer = self.get_buffer(ids[0])
output += buffer.get_slot_contents(ids[0], ids[1])
# If we are here, we should have a buffer or a buffer.slotname
output += self.get_buffer_data(item)

print(output)

def buffer(self, *args):
"""
Provides the "buffer" command.
Prints the contents of a buffer or a buffer's slot.

Examples:
!print>
buffer retrieval
buffer retrieval.word
"""
name = ''.join(args)
contents = self.get_buffer_data(name)
print(f"{name}: {contents}")

def get_buffer_data(self, item: str) -> str:
"""
Given an "item" which is either a <buffer name> or a <buffer name>.<slot name>,
return the contents.
"""
ids = item.split('.')
match len(ids):
case 1:
contents = self.get_buffer_contents(item)
case 2:
contents = self.get_slot_contents(
ids[0], ids[1])
case _:
print(
'ERROR: expected <buffer> or <buffer>.<slot_name>, found \'' +
item + '\'')
raise KeyError
return contents

def get_buffer_contents(self, buffer_name: str) -> str:
"""
Gets all the contents of a buffer.
"""
buffer = self.get_buffer(buffer_name)
data = buffer._data

if data:
return str(data.copy().pop())
else:
return "<empty>"

def get_slot_contents(self, buffer_name: str, slot_name: str) -> str:
"""
Gets the contents of a specific buffer slot.
"""
buffer = self.get_buffer(buffer_name)

if buffer._data:
chunk = buffer._data.copy().pop()
else:
chunk = None

try:
return str(getattr(chunk, slot_name))
except AttributeError:
print('ERROR: no slot named \'' + slot_name +
'\' in buffer \'' + buffer_name + '\'')
raise

def get_buffer(self, buffer_name: str) -> Buffer:
"""
Gets a buffer by name and returns it.
Expand Down