> ## Documentation Index
> Fetch the complete documentation index at: https://docs.labelbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Issues & comments

> Developer guide for creating and modifying issues and comments via the Python SDK.

## Issue categories

<CodeGroup>
  ```python Python theme={null}
  project = client.get_project("<PROJECT_ID>")

  # Create
  category = project.create_issue_category(
      name="Quality",
      description="Quality-related issues",
  )

  # List all
  categories = project.get_issue_categories()

  # Update
  category = category.update(name="Renamed", description="New description")

  # Delete
  category.delete()
  ```
</CodeGroup>

## Issues

<CodeGroup>
  ```python Python theme={null}
  from labelbox import IssueStatus, ImageIssuePosition, VideoIssuePosition, VideoFrameRange

  # Create -- minimal
  issue = project.create_issue(
      content="General quality issue",
      data_row_id="<DATA_ROW_ID>",
  )

  # Create -- with label, category, and position
  issue = project.create_issue(
      content="Bounding box is misaligned",
      data_row_id="<DATA_ROW_ID>",
      label_id="<LABEL_ID>",
      category_id=category.id,
      position=ImageIssuePosition(x=100, y=200),
  )

  # Also accepts DataRow/Label/IssueCategory objects directly
  issue = project.create_issue(
      content="Using objects instead of IDs",
      data_row_id=data_row,       # DataRow object
      label_id=label,             # Label object
      category_id=category,       # IssueCategory object
  )

  # Fetch with filters (returns PaginatedCollection)
  for issue in project.get_issues(status=IssueStatus.OPEN):
      print(issue.friendly_id, issue.content)

  # Other available filters
  project.get_issues(
      data_row_id="<DATA_ROW_ID>",
      category_id="<CATEGORY_ID>",
      created_by_ids=["<USER_ID>"],
      content="search text",
  )

  # Fetch single issue
  issue = project.get_issue("<ISSUE_ID>")

  # Update (only provided fields are changed)
  issue = issue.update(content="Updated text")
  issue = issue.update(category_id="<NEW_CATEGORY_ID>")

  # Resolve / Reopen
  issue = issue.resolve()
  issue = issue.reopen()

  # Lazy-loaded related objects (each makes an API call)
  data_row = issue.data_row()     # Optional[DataRow]
  label = issue.label()           # Optional[Label]
  category = issue.category()     # Optional[IssueCategory]

  # Delete single
  issue.delete()

  # Bulk delete
  project.delete_issues(["<ISSUE_ID_1>", "<ISSUE_ID_2>"])
  ```
</CodeGroup>

## Comments

<CodeGroup>
  ```python Python theme={null}
  # Create
  comment = issue.create_comment(content="I agree, this needs fixing")

  # List all comments on an issue
  comments = issue.comments()

  # Update
  comment = comment.update(content="Revised comment")

  # Delete
  comment.delete()
  ```
</CodeGroup>

## Video position variants

<CodeGroup>
  ```python Python theme={null}
  # Single frame
  VideoIssuePosition(frames=[
      VideoFrameRange(start=5, end=5, x=100, y=200)
  ])

  # Contiguous range (stationary pin)
  VideoIssuePosition(frames=[
      VideoFrameRange(start=5, end=11, x=450, y=300)
  ])

  # Contiguous range (moving pin)
  VideoIssuePosition(frames=[
      VideoFrameRange(start=5, end=11, x=450, y=300, end_x=500, end_y=350)
  ])

  # Multiple separated ranges
  VideoIssuePosition(frames=[
      VideoFrameRange(start=5, end=11, x=450, y=300),
      VideoFrameRange(start=20, end=25, x=100, y=100),
  ])
  ```
</CodeGroup>

## Addendum: Position formats for different data types

<CodeGroup>
  ```python Python theme={null}
  # PDF (%)
  PdfIssuePosition(x=0.5, y=0.75, page=2)

  # Text (Char range)
  TextIssuePosition(text_block_id="b1", start_char_index=10, end_char_index=25)

  # Video (Multiple frames/paths)
  VideoIssuePosition(frames=[
      VideoFrameRange(start=5, end=11, x=450, y=300, end_x=500, end_y=350),
      VideoFrameRange(start=20, end=25, x=100, y=100)
  ])
  ```
</CodeGroup>
