Working with Entries#
Entries are the fundamental building blocks of a LabArchives page. They contain the actual data, such as rich text, plain text, headers, file attachments, and widgets.
Accessing Entries#
You can access the entries of a NotebookPage through its entries property. This property returns an Entries object, which behaves like a sequence of entries.
page = notebook.traverse("Project A/Experiment 1/Results")
# Get the number of entries
print(len(page.entries))
# Iterate over entries
for entry in page.entries:
print(f"ID: {entry.id}, Type: {entry.content_type}")
# Access an entry by index
first_entry = page.entries[0]
Entry Types#
LabArchives supports several entry types. In labapi, each type is represented by a specific class inheriting from Entry.
Text-based Entries#
Text-based entries store their content as strings.
Rich Text Entry (
TextEntry): Used for formatted text, typically HTML. Content type:"text entry". See MDN HTML documentation for supported markup patterns.Plain Text Entry (
PlainTextEntry): Used for unformatted, raw text. Content type:"plain text entry".Header Entry (
HeaderEntry): Used for headings or titles within a page. Content type:"heading".
# Accessing text content
text_entry = page.entries[0]
print(text_entry.content)
# Updating rich text content
text_entry.content = "<p>Updated <strong>rich text</strong> content</p>"
Attachment Entries#
Attachment entries (AttachmentEntry) represent file attachments. Their content is an Attachment object.
attachment_entry = page.entries[1]
attachment = attachment_entry.content
print(f"Filename: {attachment.filename}")
print(f"MIME Type: {attachment.mime_type}")
print(f"Caption: {attachment.caption}")
# Read the file data
data = attachment.read()
Widget Entries#
Widget entries (WidgetEntry) embed interactive content or external applications. Like text entries, their content is represented as a string (often JSON or HTML).
Note
Widget entries are currently read-only in labapi. Their content property returns the widget’s internal data as a JSON-formatted string.
If LabArchives returns an entry type that labapi does not model yet,
entries wraps it as
UnknownEntry and emits a warning instead
of silently dropping it.
Creating New Entries#
You can create new entries using the create() method.
from labapi import TextEntry, HeaderEntry, PlainTextEntry
# Create a rich text entry (HTML is rendered in LabArchives)
page.entries.create(TextEntry, "<h2>New Section</h2><p>Some <em>formatted</em> content...</p>")
# Create a heading (displayed as a section label/divider)
page.entries.create(HeaderEntry, "Experiment Notes")
# Create a plain text entry (displayed literally)
page.entries.create(PlainTextEntry, "<h2>Raw instrument output</h2>")
Creating Attachments#
To create an attachment entry, you first need to create an Attachment object.
from io import BytesIO
from labapi import Attachment, AttachmentEntry
# Create attachment from in-memory data
data = BytesIO(b"Hello, LabArchives!")
attachment = Attachment(data, "text/plain", "hello.txt", "A simple text file")
# Upload as a new entry
page.entries.create(AttachmentEntry, attachment)
You can also create an attachment directly from a file on disk:
from labapi import Attachment, AttachmentEntry
with open("data.csv", "rb") as f:
attachment = Attachment.from_file(f)
page.entries.create(AttachmentEntry, attachment)
Working with JSON Data#
A common pattern is to store structured data as a JSON attachment with a formatted preview in a companion text entry. The create_json_entry() method simplifies this.
data = {
"experiment_id": "EXP-123",
"results": [1.2, 3.4, 5.6],
"status": "complete"
}
# Creates both an attachment entry and a text entry preview
file_entry, text_entry = page.entries.create_json_entry(data)
Modifying Entries#
To modify an entry, simply set its content property. The change is automatically synchronized with the LabArchives server.
entry = page.entries[0]
entry.content = "New content for the entry"
For attachments, setting the content property with a new Attachment object will update the file.
with open("updated_data.csv", "rb") as f:
new_attachment = Attachment.from_file(f)
attachment_entry.content = new_attachment