World¶
Example data¶
The examples use this data and the names todo, today and tasks.
import datetime as dt
from enum import StrEnum
from string.templatelib import Template
from scriptt.world import Fact, Goal, Key, Log, Ref, Row, World
class TodoList(Fact):
name: Key[str]
class Status(StrEnum):
OPEN = "open"
DONE = "done"
class Task(Fact):
id: Key[str]
list: Ref[TodoList]
title: str
status: Status = Status.OPEN
due: dt.date | None = None
def __describe__(self) -> Template: # how say() names a task
return t"task {self.id}"
class Note(Fact):
task: Key[Ref[Task]]
text: str
todo = World.new(TodoList, Task, Note)
for name in ["home", "work"]:
todo.add(
TodoList(name=name),
source="me",
true_from="2 Nov 2026",
known="2 Nov 2026 09:00",
)
for key, home, title, due, true_from, known in [
("t1", "home", "Buy milk", dt.date(2026, 11, 3), "2 Nov 2026", "2 Nov 2026 09:00"),
(
"t2",
"work",
"Send the report",
dt.date(2026, 11, 4),
"2 Nov 2026",
"2 Nov 2026 09:00",
),
(
"t3",
"work",
"Book the room",
dt.date(2026, 11, 6),
"2 Nov 2026",
"2 Nov 2026 09:00",
),
("t4", "home", "Call the plumber", None, "2 Nov 2026", "2 Nov 2026 09:00"),
(
"t5",
"home",
"Water the plants",
dt.date(2026, 11, 4),
"2 Nov 2026",
"2 Nov 2026 09:00",
),
(
"t6",
"home",
"Pay the rent",
dt.date(2026, 11, 5),
"3 Nov 2026",
"3 Nov 2026 12:00",
),
]:
todo.add(
Task(id=key, list=home, title=title, due=due),
source="me",
true_from=true_from,
known=known,
)
for task, text in [("t1", "Oat milk"), ("t2", "Use the new template")]:
todo.add(
Note(task=task, text=text),
source="me",
true_from="2 Nov 2026",
known="2 Nov 2026 09:00",
)
milk = todo.on("2 Nov 2026").one(Task, id="t1")
todo.add(
milk.but(status=Status.DONE),
source="me",
true_from="3 Nov 2026",
known="3 Nov 2026 18:30",
)
today = todo.on("4 Nov 2026")
tasks = today.facts(Task)
World
dataclass
¶
World(
_store: Store = Store(),
_types: dict[str, type[Fact]] = dict(),
on_date: date = today(),
known_time: datetime | None = None,
until_date: date | None = None,
_supposed: tuple[Entry, ...] = (),
_cache: dict = dict(),
)
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
Make a world¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
size
property
¶
size: int
The number of entries in the log.
Each of these calls adds 1 entry.
addendretractsamemapplacerename
A supposed change is not an entry.
Example
todo.size # -> 11
open
classmethod
¶
Open a world that is kept in a DuckDB file. An existing file keeps its log. So you read it again.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
The path of the DuckDB file. A new file is made if it does not exist. |
required |
*types
|
type[Fact]
|
The types of fact that the file contains. |
()
|
on
|
Moment | None
|
The day of the first view. The default |
None
|
Returns:
| Type | Description |
|---|---|
World
|
A world. Its |
Example
import pathlib
import tempfile
from scriptt.world import World
path = pathlib.Path(tempfile.mkdtemp()) / "tasks.duckdb"
kept = World.open(path, Task)
kept.add(Task(id="t9", list="home", title="Buy tea"), source="me")
kept.size # -> 1
new
classmethod
¶
Make a world that is kept in memory. The log is lost when the program ends.
Use World.open to keep it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*types
|
type[Fact]
|
The types of fact that the world contains. |
()
|
on
|
Moment | None
|
The day of the first view. The default |
None
|
Returns:
| Type | Description |
|---|---|
World
|
A new empty world. The built-in types |
World
|
included. |
Example
from scriptt.world import World
fresh = World.new(TodoList, Task, on="2 Nov 2026")
fresh.size # -> 0
fresh.on_date # -> datetime.date(2026, 11, 2)
Write to the log¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
add ¶
add(
fact: Fact,
*,
source: str,
true_from: Moment | None = None,
true_until: Moment | None = None,
true_on: Moment | None = None,
known: Moment | None = None,
once: bool = False,
) -> Self
Add a fact to the log. Give where it came from and when it is true and known.
Use true_from and true_until for a period. Use true_on for 1 day. A fact
with none of them is true for all time.
A new add with the same key is a new version of the fact. Forward[...] fields
may not move back.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fact
|
Fact
|
The fact to add. |
required |
source
|
str
|
Text that says where the fact came from. It is not optional. |
required |
true_from
|
Moment | None
|
The first day on which the fact is true. The default |
None
|
true_until
|
Moment | None
|
The day on which the fact stops being true. This day is not
included. The default |
None
|
true_on
|
Moment | None
|
One day on which the fact is true. It sets |
None
|
known
|
Moment | None
|
The time at which you got the fact. The default |
None
|
once
|
bool
|
Whether to do nothing if this source already gave this version with
the same dates. The default is
|
False
|
Returns:
| Type | Description |
|---|---|
Self
|
The same world. So you can chain calls. |
Raises:
| Type | Description |
|---|---|
ValueError
|
A date or time in the text form that |
ValueError
|
A |
Example
listed = World.new(Task)
listed.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
known="2 Nov 2026 09:00",
)
listed.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
known="2 Nov 2026 09:00",
once=True,
)
listed.size # -> 1
listed.on("2 Nov 2026").get(Task, id="t9").title # -> 'Buy tea'
end ¶
end(
fact: Fact | type[Fact],
/,
*,
on: Moment,
source: str,
known: Moment | None = None,
**key: Any,
) -> Self
Say that a fact stops being true on a day. Views before that day still see it.
An end cuts the versions that start before it. An add from the end day on
starts a new period.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fact
|
Fact | type[Fact]
|
A fact or the type of the fact. If you give a type, also give the key fields as keyword arguments. |
required |
on
|
Moment
|
The day on which the fact stops being true. This day is not included. |
required |
source
|
str
|
Text that says where this information came from. |
required |
known
|
Moment | None
|
The time at which you got this information. The default |
None
|
**key
|
Any
|
The key fields of the fact when |
{}
|
Returns:
| Type | Description |
|---|---|
Self
|
The same world. |
Raises:
| Type | Description |
|---|---|
ValueError
|
A date or time in the text form that |
KeyError
|
|
Example
listed = World.new(Task)
listed.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
listed.end(Task, id="t9", on="4 Nov 2026", source="me: not needed")
listed.on("3 Nov 2026").get(Task, id="t9").title # -> 'Buy tea'
listed.on("4 Nov 2026").get(Task, id="t9") # -> None
retract ¶
retract(
fact: Fact | type[Fact],
/,
*,
source: str,
known: Moment | None = None,
**key: Any,
) -> Self
Say that a fact was never true. Views that you knew before the retract still see it.
The log keeps the fact and adds a retract entry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fact
|
Fact | type[Fact]
|
A fact or the type of the fact. If you give a type, also give the key fields as keyword arguments. |
required |
source
|
str
|
Text that says where this information came from. |
required |
known
|
Moment | None
|
The time at which you got this information. The default |
None
|
**key
|
Any
|
The key fields of the fact when |
{}
|
Returns:
| Type | Description |
|---|---|
Self
|
The same world. |
Raises:
| Type | Description |
|---|---|
KeyError
|
|
Example
listed = World.new(Task)
listed.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
known="2 Nov 2026 20:00",
)
listed.retract(
Task,
id="t9",
source="me: typed by mistake",
known="2 Nov 2026 21:00",
)
listed.on("3 Nov 2026").get(Task, id="t9") # -> None
listed.known("2 Nov 2026 20:30").on("3 Nov 2026").get(
Task, id="t9"
).title # -> 'Buy tea'
listed.size # -> 2
same ¶
Say that 2 facts are 1 thing.
The thing keeps the identity of the fact that joined first. Its fields merge.
The newest value that is not None
wins. A later same that repeats or reverses a join changes nothing. Use
conflicts to see fields that disagree.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
Fact
|
The first fact. |
required |
b
|
Fact
|
The second fact. It must have the same type as |
required |
source
|
str
|
Text that says where this information came from. |
required |
known
|
Moment | None
|
The time at which you got this information. The default |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The same world. |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
Example
lists = World.new(Task)
a = Task(id="t9", list="home", title="Buy tea")
b = Task(id="t10", list="home", title="Get tea")
lists.add(a, source="me", true_from="2 Nov 2026").add(
b, source="me", true_from="2 Nov 2026"
)
lists.same(a, b, source="me: one task")
lists.on("2 Nov 2026").facts(Task).count() # -> 1
map ¶
map(
a: Any,
b: Any,
match: Match,
*,
source: str,
true_from: Moment | None = None,
known: Moment | None = None,
) -> Self
Say that a term in 1 word list maps to a term in another.
This adds a Mapping fact. Read the mappings of a term with mapped.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
Any
|
The term in the first word list. An enum member uses its value. |
required |
b
|
Any
|
The term in the other word list. |
required |
match
|
Match
|
The kind of the mapping. |
required |
source
|
str
|
Text that says where this information came from. |
required |
true_from
|
Moment | None
|
The first day on which the mapping is true. The default |
None
|
known
|
Moment | None
|
The time at which you got this information. The default |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The same world. |
Example
from scriptt.world import Match, World
terms = World.new()
terms.map("shopping", "errands", Match.NARROWER, source="me")
terms.mapped("shopping").count() # -> 1
place ¶
place(
child: Any,
*,
under: Any,
source: str,
rel: Rel = PART_OF,
true_from: Moment | None = None,
true_until: Moment | None = None,
known: Moment | None = None,
) -> Self
Say that a thing is directly under a parent. The thing is a part of the
parent (the default) or a kind of the parent (rel=Rel.IS_A).
This adds an Under fact. A thing has 1 parent for each kind of link. A later
place of the same child and
kind replaces the parent. Read the tree with these calls.
parentschildrenancestorsdescendants
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
child
|
Any
|
The thing. An enum member uses its value. |
required |
under
|
Any
|
The parent. |
required |
rel
|
Rel
|
The kind of link. The default is |
PART_OF
|
source
|
str
|
Text that says where this information came from. |
required |
true_from
|
Moment | None
|
The first day on which the place is true. The default |
None
|
true_until
|
Moment | None
|
The day on which it stops. This day is not included. The default
|
None
|
known
|
Moment | None
|
The time at which you got this information. The default |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The same world. |
Raises:
| Type | Description |
|---|---|
ValueError
|
A date or time in the text form that |
Example
tree = World.new()
tree.place("Buy milk", under="Groceries", source="me")
tree.parents("Buy milk").first() # -> 'Groceries'
rename ¶
Say that a field of a type now has a new name. Earlier entries are read with the new name.
Declare the new field on the type first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
of
|
type[Fact]
|
The type with the new field already declared. |
required |
old
|
str
|
The old name of the field. |
required |
new
|
str
|
The new name of the field. |
required |
source
|
str
|
Text that says where this information came from. |
required |
known
|
Moment | None
|
The time at which you got this information. The default |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The same world. |
Raises:
| Type | Description |
|---|---|
KeyError
|
The type has no field with the new name. |
Example
class Chore(Fact, name="chore"):
id: Key[str]
hours: float
class ChoreNow(Fact, name="chore"):
id: Key[str]
minutes: float
chores = World.new(Chore)
chores.add(Chore(id="t9", hours=1.5), source="me")
chores.rename(ChoreNow, old="hours", new="minutes", source="me: new name")
chores.get(ChoreNow, id="t9").minutes # -> 1.5
Views¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
on ¶
Give a view of the world on a day.
The view keeps the facts that are true on that day. It does not change what the view knows.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
date
|
Moment
|
The day. A time of day is ignored. A time zone does not move the day. |
required |
Returns:
| Type | Description |
|---|---|
World
|
A new view of the same log. |
Raises:
| Type | Description |
|---|---|
ValueError
|
A date or time in the text form that |
Example
todo.on("2 Nov 2026").facts(Task).count() # -> 5
todo.on("4 Nov 2026").facts(Task).count() # -> 6
known ¶
Give a view that knows only what you knew by a time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time
|
Moment
|
The time. A date with no time of day means the end of that day. |
required |
Returns:
| Type | Description |
|---|---|
World
|
A new view of the same log. Its |
Raises:
| Type | Description |
|---|---|
ValueError
|
A date or time in the text form that |
Example
view = todo.on("4 Nov 2026").known("2 Nov 2026 09:00")
view.facts(Task).count() # -> 5
at ¶
Give the world as you saw it on a day. It has the facts true on that day and known by the end of it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
date
|
Moment
|
The day. |
required |
Returns:
| Type | Description |
|---|---|
World
|
A new view of the same log. |
Raises:
| Type | Description |
|---|---|
ValueError
|
A date or time in the text form that |
Example
todo.at("4 Nov 2026").known_time
# -> datetime.datetime(2026, 11, 4, 23, 59, 59, 999999)
during ¶
Give a window of days. A fact is in the view if it was true on any day of the window.
The window starts on start and ends before until. A fact with 2 versions in
the window is seen once. It shows its latest
version. history gives every version.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
Moment
|
The first day of the window. |
required |
until
|
Moment
|
The day after the last day of the window. This day is not in the window. |
required |
Returns:
| Type | Description |
|---|---|
World
|
A new view of the same log. |
Raises:
| Type | Description |
|---|---|
ValueError
|
A date or time in the text form that |
Example
listed = World.new(Task)
listed.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
listed.end(Task, id="t9", on="4 Nov 2026", source="me: not needed")
listed.add(
Task(id="t9", list="home", title="Buy more tea"),
source="me: again",
true_from="10 Nov 2026",
)
listed.during("3 Nov 2026", "11 Nov 2026").get(Task, id="t9").title
# -> 'Buy more tea'
steps ¶
Give a series of views from this view's day. There is one view for each step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
by
|
Step
|
The distance between the views. |
required |
count
|
int
|
The number of views. The first view is on this view's day. |
required |
known_too
|
bool
|
Whether each view knows only what you knew by the end of its day.
The default |
False
|
Returns:
| Type | Description |
|---|---|
Facts[World]
|
A collection of |
Raises:
| Type | Description |
|---|---|
ValueError
|
A date or time in the text form that |
Example
from scriptt.world import Step
views = todo.on("2 Nov 2026").steps(Step.DAY, 3)
[view.facts(Task).count() for view in views] # -> [5, 6, 6]
suppose ¶
suppose(
*,
add: Iterable[Fact] = (),
true_from: Moment | None = None,
end: Iterable[Fact] = (),
retract: Iterable[Fact] = (),
) -> World
Give a view with changes that the log does not keep.
A supposed fact wins over every logged fact. A supposed end uses the day of this
view. Ask what would differ with
supposed - today.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
add
|
Iterable[Fact]
|
Facts to add. The default is none. |
()
|
true_from
|
Moment | None
|
The first day on which the added facts are true. The default
|
None
|
end
|
Iterable[Fact]
|
Facts to end on this view's day. The default is none. |
()
|
retract
|
Iterable[Fact]
|
Facts that were never true. The default is none. |
()
|
Returns:
| Type | Description |
|---|---|
World
|
A new view. The log does not change. |
Example
report = today.one(Task, id="t2")
done = today.suppose(add=[report.but(status=Status.DONE)])
done.one(Task, id="t2").status.value # -> 'done'
today.one(Task, id="t2").status.value # -> 'open'
Read facts¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
facts ¶
facts(of: type[T]) -> Facts[T]
Give every fact of 1 type that is true in this view.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
of
|
type[T]
|
The type of fact. |
required |
Returns:
| Type | Description |
|---|---|
Facts[T]
|
A collection of facts with 1 fact for each thing. Versions merge as |
Facts[T]
|
says. A type that other types subclass |
Facts[T]
|
( |
Example
today.facts(Task).count() # -> 6
today.facts(Note).count() # -> 2
one ¶
one(of: type[T], **key: Any) -> T
Give 1 fact by its key fields. The fact must exist in this view.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
of
|
type[T]
|
The type of fact. |
required |
**key
|
Any
|
A value for every key field of the type. |
{}
|
Returns:
| Type | Description |
|---|---|
T
|
The fact. |
Raises:
| Type | Description |
|---|---|
LookupError
|
No fact of this type with this key is true in this view. Use
|
KeyError
|
You did not give all the key fields. |
Example
today.one(Task, id="t2").title # -> 'Send the report'
get ¶
get(of: type[T], **key: Any) -> T | None
Give 1 fact by its key fields. It is None if the fact is not true in this
view.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
of
|
type[T]
|
The type of fact. |
required |
**key
|
Any
|
A value for every key field of the type. |
{}
|
Returns:
| Type | Description |
|---|---|
T | None
|
The fact or |
Raises:
| Type | Description |
|---|---|
KeyError
|
You did not give all the key fields. |
Example
today.get(Task, id="t99") # -> None
Read the log¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
history ¶
Give every entry of the log for 1 fact with all 3 times. The oldest entry comes first.
The entries are those that the view knows. Supposed changes are at the end.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fact
|
Fact
|
A fact. Its type and key choose the entries. |
required |
Returns:
| Type | Description |
|---|---|
Facts[Entry]
|
A collection of |
Example
listed = World.new(Task)
listed.add(Task(id="t9", list="home", title="Buy tea"), source="me")
listed.add(Task(id="t9", list="home", title="Buy tea x2"), source="me: x2")
probe = Task(id="t9", list="", title="")
[entry.source for entry in listed.history(probe)]
# -> ['me', 'me: x2']
origin ¶
origin(
fact: T, field: Callable[[T], V]
) -> Origin[T, V]
Say where 1 value of a fact came from. Give the value and the entry of the log that wrote it.
For a fact of this view, the entry is the one that wrote the version that this
view shows. After same it is
the entry of the member that gave the value. Give a changed copy to find when
another value was written. An example is
view.origin(fact.but(p=0.5), lambda f: f.p). Then the entry is the first of
the last run of entries that give it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fact
|
T
|
The fact. |
required |
field
|
Callable[[T], V]
|
A function that reads exactly 1 field of the fact. An example is
|
required |
Returns:
| Type | Description |
|---|---|
Origin[T, V]
|
An |
Raises:
| Type | Description |
|---|---|
ValueError
|
The function does not read exactly 1 field of the fact. |
LookupError
|
No entry of the log gives the fact this value. |
Example
report = today.one(Task, id="t2")
today.origin(report, lambda t: t.title).entry.known
# -> datetime.datetime(2026, 11, 2, 9, 0)
References, kinds and problems¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
problems ¶
Give every problem in this view. A problem is one of these.
- A
Reffield that points to no fact. - A thing that
placeputs under itself. - A fact that a goal fails.
A Ref problem is found for every type in the world with no setup. A goal adds
its own rule. A goal with
every=True gives 1 problem for each fact that fails it. A count or sum goal
that is not met gives 1 problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*goals
|
Goal
|
Rules to check as well. A rule such as "at most 1 employer at a
time" is a goal with |
()
|
Returns:
| Type | Description |
|---|---|
Facts[Problem]
|
A collection of problems. The |
Facts[Problem]
|
means no problem. |
Example
from scriptt.world import Fact, Key, Ref, World
class TodoList(Fact):
name: Key[str]
class Task(Fact):
id: Key[str]
list: Ref[TodoList]
title: str
lists = World.new(TodoList, Task)
lists.add(TodoList(name="home"), source="me")
lists.add(Task(id="t1", list="home", title="Buy milk"), source="me").add(
Task(id="t2", list="work", title="Send the report"), source="me"
)
[p.message for p in lists.problems()]
# -> ["task t2: list 'work' is not the key of any TodoList."]
about ¶
Give the fact and every fact that points to it with a Ref field. This gives
"everything about this thing".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fact
|
Fact
|
The fact. An example is a list. |
required |
hops
|
int
|
How many references to follow back. 2 also gives the facts that point to those facts (the notes of the tasks of a list). The default is 1. |
1
|
Returns:
| Type | Description |
|---|---|
Facts[Fact]
|
A collection with the fact first. Then come the facts that point to it. They |
Facts[Fact]
|
come type by type. A |
Facts[Fact]
|
it subclasses counts too. |
Example
from scriptt.world import Fact, Key, Ref, World
class TodoList(Fact):
name: Key[str]
class Task(Fact):
id: Key[str]
list: Ref[TodoList]
title: str
lists = World.new(TodoList, Task)
lists.add(TodoList(name="home"), source="me")
lists.add(Task(id="t1", list="home", title="Buy milk"), source="me").add(
Task(id="t2", list="work", title="Send the report"), source="me"
)
lists.about(lists.one(TodoList, name="home")).count()
# -> 2: the list and its task
parents ¶
Give the direct parent of a thing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
thing
|
Any
|
The thing. An enum member uses its value. |
required |
rel
|
Rel
|
The kind of link to follow. The default is |
PART_OF
|
Returns:
| Type | Description |
|---|---|
Facts[str]
|
A collection of 0 or 1 text value. |
Example
tree = World.new()
tree.place("Buy milk", under="Groceries", source="me")
list(tree.parents("Buy milk")) # -> ['Groceries']
children ¶
Give the things that are directly under a thing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
thing
|
Any
|
The parent. An enum member uses its value. |
required |
rel
|
Rel
|
The kind of link to follow. The default is |
PART_OF
|
Returns:
| Type | Description |
|---|---|
Facts[str]
|
A collection of text values. |
Example
tree = World.new()
tree.place("Buy milk", under="Groceries", source="me")
list(tree.children("Groceries")) # -> ['Buy milk']
ancestors ¶
Give the parent of a thing and the parent of that parent and so on. The nearest comes first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
thing
|
Any
|
The thing. An enum member uses its value. |
required |
rel
|
Rel
|
The kind of link to follow. The default is |
PART_OF
|
Returns:
| Type | Description |
|---|---|
Facts[str]
|
A collection of text values. It stops if the tree has a loop. |
Example
tree = World.new()
tree.place("Buy milk", under="Groceries", source="me")
tree.place("Groceries", under="Shopping", source="me")
list(tree.ancestors("Buy milk"))
# -> ['Groceries', 'Shopping']
descendants ¶
Give every thing under a thing at any depth. The nearest come first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
thing
|
Any
|
The parent. An enum member uses its value. |
required |
rel
|
Rel
|
The kind of link to follow. The default is |
PART_OF
|
Returns:
| Type | Description |
|---|---|
Facts[str]
|
A collection of text values. |
Example
tree = World.new()
tree.place("Buy milk", under="Groceries", source="me")
tree.place("Groceries", under="Shopping", source="me")
list(tree.descendants("Shopping"))
# -> ['Groceries', 'Buy milk']
conflicts ¶
Give the fields on which the members of 1 thing disagree after same.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
of
|
type[Fact]
|
The type of fact. |
required |
Returns:
| Type | Description |
|---|---|
Facts[Conflict]
|
A collection of |
Facts[Conflict]
|
more. |
Example
lists = World.new(Task)
a = Task(id="t9", list="home", title="Buy tea")
b = Task(id="t10", list="home", title="Get tea")
lists.add(a, source="me").add(b, source="me").same(
a, b, source="me: one task"
)
lists.conflicts(Task)[0].values # -> ('Buy tea', 'Get tea')
mapped ¶
Give the mappings from a term in either direction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
term
|
Any
|
The term. An enum member uses its value. |
required |
match
|
Match | None
|
The kind of mapping to keep. The default |
None
|
Returns:
| Type | Description |
|---|---|
Facts[Mapping]
|
A collection of |
Example
from scriptt.world import Match, World
terms = World.new()
terms.map("shopping", "errands", Match.NARROWER, source="me")
terms.mapped("errands", Match.NARROWER)[0].a # -> 'shopping'
Compare views¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
__sub__ ¶
Compare 2 views as later - earlier. Give the facts that the later view adds
or removes or changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
earlier
|
World
|
The view to compare with. It must share the log or at least use the same types. |
required |
Returns:
| Type | Description |
|---|---|
Changes[Fact]
|
A |
Example
earlier = todo.on("4 Nov 2026").known("2 Nov 2026 09:00")
changes = today - earlier
changes.added.count(), changes.removed.count() # -> (1, 0)
Goals¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
check ¶
check(goal: Goal[T]) -> GoalResult[T]
Test a goal in this view.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
goal
|
Goal[T]
|
The goal. The second parameter of a rule with 2 parameters is this view. |
required |
Returns:
| Type | Description |
|---|---|
GoalResult[T]
|
A |
GoalResult[T]
|
that fail the rule. |
Example
has_note = Goal(
"every task has a note",
Task,
lambda t, view: view.get(Note, task=t.id) is not None,
every=True,
)
result = today.check(has_note)
result.met, sorted(t.id for t in result.failing)
# -> (False, ['t3', 't4', 't5', 't6'])
SQL and export¶
A log of facts and a view of it on 1 date with what you knew at 1 time. Every view of 1 log shares that log.
Make a world with World.new or World.open. Do not call the constructor. Writing
calls such as add and end and retract
add to the log. Every other call gives a new view or an answer. It does not change
the log.
A view has 3 fields. You can read them. These calls make views with other values.
onknownatduringsteps
Attributes:
| Name | Type | Description |
|---|---|---|
on_date |
date
|
The day of the view. The default is today. In a |
known_time |
datetime | None
|
The latest time that the view knows. The default |
until_date |
date | None
|
The end of a |
Example
from scriptt.world import World
todo = World.new(TodoList, Task)
todo.add(
Task(id="t9", list="home", title="Buy tea"),
source="me",
true_from="2 Nov 2026",
)
todo.on("2 Nov 2026").one(Task, id="t9").title # -> 'Buy tea'
sql ¶
Run SQL for a question that the verbs do not cover. Give the query as a t-string.
{Task} names the typed table of a fact type in this view. {Log} names the
log. Every other {value} is sent as a
parameter and is never pasted into the query. Only 1 SELECT or PIVOT or UNPIVOT
or EXPLAIN runs. So the log cannot change.
DuckDB can still read local files (read_csv and read_text). Write {Log}
and do not write log. The plain table contains
every entry. This includes entries that the view does not know yet.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
Template
|
A t-string. A value in it takes no format and no conversion. |
required |
Returns:
| Type | Description |
|---|---|
Facts[Row]
|
A collection of rows with 1 for each row of the result. The column names are |
Facts[Row]
|
the field names. |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
ValueError
|
A value has a format or a conversion or the text is not 1 SELECT or PIVOT or UNPIVOT or EXPLAIN. |
Example
limit = dt.date(2026, 11, 4)
rows = today.sql(
t"FROM {Task} SELECT title, due WHERE due > {limit} ORDER BY due DESC"
)
rows[0].title # -> 'Book the room'
relation ¶
relation(of: type[Fact]) -> DuckDBPyRelation
Give the facts of 1 type in this view as a DuckDB relation with typed columns. An enum field is a DuckDB ENUM.
Each call makes its own table. So a relation keeps its rows when you make another view.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
of
|
type[Fact]
|
The type of fact. |
required |
Returns:
| Type | Description |
|---|---|
DuckDBPyRelation
|
A |
Example
len(today.relation(Task)) # -> 6
frame ¶
frame(of: type[Fact]) -> DataFrame
Give the facts of 1 type as a Polars DataFrame. It has 1 row for each fact.
This needs the extra scriptt[frames].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
of
|
type[Fact]
|
The type of fact. |
required |
Raises:
| Type | Description |
|---|---|
ModuleNotFoundError
|
Polars is not installed. |
Example
today.frame(Note).shape # -> (2, 2)
export ¶
export(folder: str | Path) -> Facts[Path]
Write 1 Parquet file for each type that has facts in this view.
Each file is named after the type. An example is task.parquet.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
folder
|
str | Path
|
The folder for the files. It is made if it does not exist. |
required |
Returns:
| Type | Description |
|---|---|
Facts[Path]
|
A collection of the paths of the files. |
Example
import pathlib
import tempfile
files = today.export(pathlib.Path(tempfile.mkdtemp()))
sorted(path.name for path in files)
# -> ['note.parquet', 'task.parquet', 'todolist.parquet']