Triage status is based on three states:
English Name Numeric code Now 100.0 Later 200.0 Done 300.0
These primary values are the defaults, but arbitrary additional triage states can be defined in plugins.
>>> from chandler.triage import *
>>> from chandler.core import Item
>>> item = Item()
>>> item_triage = Triage(item)
>>> item_triage.calculated
100.0
calculated is the “real” value that should be used for displaying the current triage status. It’s read-only, based on manual and auto.
Triage status can be directly set using manual. In the simplest case, if manual is set, it overrides triage status from other sources (see Manual triage, revisited for when this doesn’t apply).
>>> item_triage.manual = LATER
>>> item_triage.calculated
200.0
manual triage status must be either None, or a float >= 100.
>>> item_triage.manual = 99
Traceback (most recent call last):
. . .
TriageRangeError: Can't set triage status to: 99
If manual is None, auto is used to determine calculated.
The auto cell is calculated by taking the highest weighted value from applying the chandler.domain.triage hook. If no values are found, NOW is used.
>>> item_triage.manual = None
>>> item_triage.calculated
100.0
XXX test triage status of unrecognized 250, calculated falls back to 200
Triage status is tightly entwined with positioning entries in the triage-sorted dashboard view.
TriagePosition of an item has a read-only float position cell. The default value is the item’s created timestamp.
>>> from chandler import time_services # set up the current time
>>> from datetime import datetime, timedelta
>>> eight_am = datetime(2008, 10, 1, 8, tzinfo=time_services.TimeZone.eastern)
>>> time_services.setNow(eight_am)
>>> time_services.timestamp(eight_am)
1222862400.0
>>> item = Item()
>>> item_position = TriagePosition(item)
>>> item_position.position
1222862400.0
>>> item_triage = Triage(item)
position is based on two cells, default_position and pinned_position.
pinned_position is used to hold an item visible in a different location than its underlying item’s default position would be. This allows item position to be stable as a user makes changes that would otherwise move the item.
>>> item_position.position == item_position.default_position
True
>>> item_position.pinned_position = 1234567890.0
>>> item_triage.manual = DONE
>>> item_position.position
1234567890.0
When sorted by triage status, items are sorted into different sections, determined by triage_section. This defaults to calculated triage status, but can be overridden with pinned_triage.
>>> item_position.triage_section
300.0
>>> item_position.pinned_triage_section = NOW
>>> item_position.triage_section
100.0
There are a few shortcuts for setting pinned values. pin() sets pinned values to match the current state of their default values, but only if no pinned values are set. clear_pinned() resets pinned values to None.
>>> item_position.default_triage_section, item_position.default_position
(300.0, 1222862400.0)
>>> item_position.triage_section, item_position.position
(100.0, 1234567890.0)
>>> item_position.pin()
>>> item_position.triage_section, item_position.position
(100.0, 1234567890.0)
>>> item_position.clear_pinned()
>>> item_position.triage_section, item_position.position
(300.0, 1222862400.0)
>>> item_position.pin()
>>> item_triage.manual = NOW
>>> item_position.triage_section, item_position.position
(300.0, 1222862400.0)
pin_to_now() sets pinned_triage_section to NOW and position to the timestamp for the current time.
>>> item_triage.manual = LATER
>>> item_position.clear_pinned()
>>> item_position.triage_section, item_position.position
(200.0, 1222862400.0)
>>> item_position.pin_to_now()
>>> item_position.triage_section, item_position.position
(100.0, 1222862400.0)
>>> item_position.clear_pinned()
In practice, position and triage status will often depend on the current time. Generally, triage can be thought of as a timeline, with certain points in time defining transitions to new triage statuses.
An Extension can define any number of transition points on the triage timeline. Triage.auto and TriagePosition.default_position will change as time passes these transition points.
To determine an item’s triage timeline, a list of (timestamp, triage_status) pairs are gathered using the triage hook. auto will be the triage status associated with the most recent past timestamp.
TriagePosition.default_position is a little more complicated. When calculated is NOW or DONE, TriagePosition.default_position is the most recent past timestamp.
When calculated is LATER, however, Chandler sorts items by the next time something will happen. Only if there are no future transition points on the triage timeline will the last past timestamp be used.
To test all this, we’ll create a few simple callbacks based on created:
>>> def done_one_hour_later(item):
... return ((item.created + 3600, DONE),)
>>> def now_two_hours_before_and_after(item):
... return ((item.created - 7200, NOW), (item.created + 7200, NOW))
>>> from peak.util import plugins
>>> from peak.events.activity import Time
>>> triage_hook = plugins.Hook('chandler.domain.triage')
>>> triage_hook.register(done_one_hour_later)
>>> triage_hook.register(now_two_hours_before_and_after)
We need to create a new item now that we’ve registered new hooks, otherwise the Trellis won’t include the hook’s dependencies when determining whether a recalculation is needed.
>>> item = Item()
>>> item_triage = Triage(item)
>>> item_position = TriagePosition(item)
>>> item_triage.calculated == NOW
True
Next, we’ll create a Performer cell to track how far position is from 8AM.
>>> def triage_details():
... delta = item_position.position - time_services.timestamp(eight_am)
... print 'position hours from 8am:', delta / 3600
... print 'auto triage status:', item_triage.auto
>>> from peak.events.trellis import Performer
>>> performer = Performer(triage_details)
position hours from 8am: 0.0
auto triage status: 100.0
Since calculated is NOW, the most recent past timestamp is used, which in this case is the default (when the item was created).
>>> item_triage.manual = LATER
position hours from 8am: 1.0
auto triage status: 100.0
When calculated changes to LATER, the earliest future timestamp is used.
>>> Time.advance(3600)
position hours from 8am: 2.0
auto triage status: 300.0
>>> item_triage.manual = DONE
position hours from 8am: 1.0
auto triage status: 300.0
>>> Time.advance(400)
>>> Time.advance(3600)
position hours from 8am: 2.0
auto triage status: 100.0
If no future timestamps are found, the behavior falls back to the latest past timestamp, so there’s no change in position if triage is set to LATER.
>>> item_triage.manual = LATER
If manual is set by itself, it takes precedence over auto when determining calculated.
More commonly, however, manual_timestamp will be set. If manual and manual_timestamp are both set, together they represent a point on the triage timeline, and manual contributes to the calculation of auto, rather than overriding it.
>>> item = Item()
>>> item_triage = Triage(item)
>>> item_triage.calculated == NOW
True
>>> item_triage.auto == NOW
True
>>> item_triage.manual = LATER
>>> item_triage.calculated == LATER
True
>>> day_later = time_services.timestamp(eight_am + timedelta(days=1))
>>> item_triage.manual_timestamp = day_later
>>> item_triage.calculated == NOW
True
>>> time_services.setNow(eight_am + timedelta(days=2))
>>> item_triage.auto == LATER, item_triage.calculated == LATER
(True, True)
>>> TriagePosition(item).position
1222948800.0
>>> day_later
1222948800.0