feat: Task Hierarchy#102
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds hierarchical tracking and representation features to span objects, enabling parent-child task relationships, run-level task aggregation, and improved debugging output.
- Introduce
tasks,all_tasks, andparent_taskproperties onRunSpanandTaskSpanfor hierarchy navigation. - Implement
__repr__,__str__, and a.failedproperty along with a_format_statushelper for consistent span status formatting. - Update documentation in
tasks.mdxandruns.mdxto illustrate the new hierarchy and usage patterns.
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| dreadnode/tracing/span.py | Added hierarchy properties, __repr__/__str__, status helper, and parent-child setup logic |
| docs/usage/tasks.mdx | Added a section and examples for task hierarchy and relationships |
| docs/usage/runs.mdx | Added a section and examples for run-level task hierarchy |
Comments suppressed due to low confidence (1)
dreadnode/tracing/span.py:87
- The new
_format_statushelper covers multiple branches (error with/without description and ok). Consider adding unit tests to verify each formatting path.
def _format_status(status: Status) -> str:
| def __repr__(self) -> str: | ||
| return ( | ||
| f"{self.__class__.__name__}(name='{self._span_name}', id={self.span_id}," | ||
| f"label='{self._label}', status={_format_status(self.status)}, active={self.is_recording})" |
There was a problem hiding this comment.
In __repr__, active references the is_recording method instead of calling it, so it prints a method object. Change self.is_recording to self.is_recording() to show the actual boolean status.
| f"label='{self._label}', status={_format_status(self.status)}, active={self.is_recording})" | |
| f"label='{self._label}', status={_format_status(self.status)}, active={self.is_recording()})" |
| super().__init__(f"run.{run_id}.update", attributes, tracer, type="run_update") | ||
|
|
||
| def __repr__(self) -> str: | ||
| status = "active" if self.is_recording else "inactive" |
There was a problem hiding this comment.
Here self.is_recording is a method, not a boolean property. Use self.is_recording() to correctly evaluate whether recording is active.
| num_objects = len(self._objects) | ||
| return ( | ||
| f"RunSpan(name='{self._span_name}', id='{run_id}', " | ||
| f"project='{project}', status={_format_status(self.status)}, active={self.is_recording}, " |
There was a problem hiding this comment.
Similar to above, active is using the is_recording method reference. It should be self.is_recording() to display the boolean state.
| f"project='{project}', status={_format_status(self.status)}, active={self.is_recording}, " | |
| f"project='{project}', status={_format_status(self.status)}, active={self.is_recording()}, " |
| parent_info = f", parent_task='{parent_task_id}'" if parent_task_id else "" | ||
| return ( | ||
| f"TaskSpan(name='{self._span_name}', label='{self._label}', " | ||
| f"run='{run_id}'{parent_info}, status={_format_status(self.status)}, active={self.is_recording}, " |
There was a problem hiding this comment.
The active field is referencing the is_recording method rather than calling it, so it won't show the actual recording status. Update to self.is_recording().
| f"run='{run_id}'{parent_info}, status={_format_status(self.status)}, active={self.is_recording}, " | |
| f"run='{run_id}'{parent_info}, status={_format_status(self.status)}, active={self.is_recording()}, " |
| return self._tasks | ||
|
|
||
| @property | ||
| def all_tasks(self) -> "list[TaskSpan[t.Any]]": |
There was a problem hiding this comment.
[nitpick] The all_tasks recursion is duplicated in both RunSpan and TaskSpan. Extracting this logic into a shared utility or base class method would reduce duplication and ease future maintenance.
Key Changes:
Added:
.failedproperty to check span error statusChanged:
Generated Summary:
runs.mdxandtasks.mdxdocumentation files.RunSpanandTaskSpanclasses:tasks: List of child tasks associated with a run or task.all_tasks: Flattened list of all tasks, including subtasks, for comprehensive analysis.parent_task: Reference to the parent task of a given task.__repr__and__str__) of theSpan,RunSpan, andTaskSpanclasses for better debugging and logging.This summary was generated with ❤️ by rigging