Create, read, and update Microsoft Word .docx files.
—
Document commenting system for adding and managing comments anchored to specific text ranges. Provides collaborative features for document review and annotation.
Access and manage the document comments collection.
class Document:
@property
def comments(self):
"""Collection of all comments in document.
Returns:
Comments: Comments collection object
"""
def add_comment(self, runs, text='', author='', initials=''):
"""Add a comment to the document.
Args:
runs (Run or list[Run]): Run or sequence of runs to anchor comment to
text (str, optional): Comment text content
author (str, optional): Comment author name
initials (str, optional): Author initials
Returns:
Comment: New comment object
"""
class Comments:
def add_comment(self, runs, text='', author='', initials=''):
"""Add a comment anchored to specified runs.
Args:
runs (Run or list[Run]): Run or sequence of runs to comment on
text (str, optional): Comment text content
author (str, optional): Comment author name
initials (str, optional): Author initials
Returns:
Comment: New comment object
"""
def __len__(self):
"""Number of comments in collection."""
def __iter__(self):
"""Iterate over comments."""
def __getitem__(self, index):
"""Access comment by index."""Usage Examples:
# Access comments collection
comments = doc.comments
print(f"Document has {len(comments)} comments")
# Add comment to a single run
para = doc.add_paragraph('This text will have a comment.')
run = para.runs[0]
comment = doc.add_comment(run, 'This is a comment', author='John Doe', initials='JD')
# Add comment through comments collection
comment2 = comments.add_comment(run, 'Another comment', author='Jane Smith')
# Iterate through all comments
for i, comment in enumerate(comments):
print(f"Comment {i+1}: {comment.text} by {comment.author}")Add comments to specific text ranges with various anchoring options.
Usage Examples:
# Add comment to single run
para = doc.add_paragraph('Text with comment.')
run = para.runs[0]
comment = doc.add_comment(run, 'Review this text', author='Reviewer')
# Add comment to multiple runs (text span)
para = doc.add_paragraph()
run1 = para.add_run('Start of ')
run2 = para.add_run('commented text ')
run3 = para.add_run('end.')
# Comment spans multiple runs
commented_runs = [run1, run2]
comment = doc.add_comment(commented_runs, 'This spans multiple runs',
author='Editor', initials='ED')
# Add comment with detailed information
para = doc.add_paragraph('Important information here.')
run = para.runs[0]
comment = doc.add_comment(
run,
'Please verify this information with the latest data.',
author='Data Analyst',
initials='DA'
)
# Add empty comment (to be filled later)
comment = doc.add_comment(run, author='Placeholder')Access and manage comment properties and content.
class Comment:
@property
def text(self):
"""Comment text content (read-only).
Returns:
str: Plain text content of all comment paragraphs
"""
@property
def author(self):
"""Comment author (read-only).
Returns:
str: Author name
"""
@property
def initials(self):
"""Author initials (read-only).
Returns:
str: Author initials
"""
@property
def paragraphs(self):
"""Paragraphs in the comment.
Returns:
list[Paragraph]: List of paragraph objects in comment
"""
@property
def tables(self):
"""Tables in the comment.
Returns:
list[Table]: List of table objects in comment
"""
def add_paragraph(self, text='', style=None):
"""Add a paragraph to the comment.
Args:
text (str, optional): Paragraph text
style (str or ParagraphStyle, optional): Paragraph style
Returns:
Paragraph: New paragraph object
"""
def add_table(self, rows, cols):
"""Add a table to the comment.
Args:
rows (int): Number of initial rows
cols (int): Number of initial columns
Returns:
Table: New table object
"""Usage Examples:
# Create comment and access properties
para = doc.add_paragraph('Commented text')
run = para.runs[0]
comment = doc.add_comment(run, 'Initial comment', author='John Doe', initials='JD')
# Access comment properties
print(f"Author: {comment.author}")
print(f"Initials: {comment.initials}")
print(f"Text: {comment.text}")
# Add additional content to comment
additional_para = comment.add_paragraph('Additional comment details.')
additional_para.runs[0].italic = True
# Add formatted content
formatted_para = comment.add_paragraph()
formatted_para.add_run('Bold comment text').bold = True
formatted_para.add_run(' and normal text.')
# Add table to comment
comment_table = comment.add_table(rows=2, cols=2)
comment_table.cell(0, 0).text = 'Issue'
comment_table.cell(0, 1).text = 'Status'
comment_table.cell(1, 0).text = 'Grammar'
comment_table.cell(1, 1).text = 'Fixed'
# Access all paragraphs in comment
for para in comment.paragraphs:
print(f"Comment paragraph: {para.text}")Complex scenarios for document review and collaboration.
Usage Examples:
# Create review workflow with multiple comments
def add_review_comment(run, issue_type, description, reviewer):
"""Add structured review comment."""
comment = doc.add_comment(run, '', author=reviewer)
# Add issue type header
header = comment.add_paragraph(f"{issue_type.upper()}", style='Strong')
# Add description
desc_para = comment.add_paragraph(description)
# Add reviewer signature
sig_para = comment.add_paragraph(f"- {reviewer}")
sig_para.runs[0].italic = True
return comment
# Usage of review function
para = doc.add_paragraph('This sentence has a potential issue.')
run = para.runs[0]
# Add different types of review comments
add_review_comment(run, 'Grammar', 'Check subject-verb agreement', 'Copy Editor')
add_review_comment(run, 'Fact Check', 'Verify statistics mentioned', 'Research Team')
add_review_comment(run, 'Style', 'Consider more concise wording', 'Style Guide Team')
# Create comment thread simulation
base_comment = doc.add_comment(run, 'Original comment', author='Author')
reply_para = base_comment.add_paragraph('Reply to comment')
reply_para.add_run(' - Reviewer Response').italic = True
# Add comment with action items
action_comment = doc.add_comment(run, '', author='Project Manager')
action_comment.add_paragraph('Action Items:')
action_table = action_comment.add_table(rows=3, cols=3)
headers = ['Task', 'Assignee', 'Due Date']
for i, header in enumerate(headers):
action_table.cell(0, i).text = header
action_table.cell(0, i).paragraphs[0].runs[0].bold = True
# Add action items
tasks = [
['Revise paragraph', 'Writer', '2024-01-15'],
['Review changes', 'Editor', '2024-01-17']
]
for row_idx, task_data in enumerate(tasks, 1):
for col_idx, data in enumerate(task_data):
action_table.cell(row_idx, col_idx).text = dataAnalyze and report on document comments.
Usage Examples:
def analyze_comments(doc):
"""Analyze document comments and generate report."""
comments = doc.comments
if len(comments) == 0:
print("No comments in document")
return
# Count comments by author
author_counts = {}
for comment in comments:
author = comment.author or 'Unknown'
author_counts[author] = author_counts.get(author, 0) + 1
print(f"Total comments: {len(comments)}")
print("\nComments by author:")
for author, count in author_counts.items():
print(f" {author}: {count}")
# List all comments
print("\nAll comments:")
for i, comment in enumerate(comments, 1):
print(f"{i}. [{comment.author or 'Unknown'}] {comment.text[:100]}...")
# Usage
analyze_comments(doc)
def extract_comment_text(doc):
"""Extract all comment text for analysis."""
all_comment_text = []
for comment in doc.comments:
# Get main comment text
main_text = comment.text
# Get text from all paragraphs (more detailed)
detailed_text = '\n'.join(para.text for para in comment.paragraphs)
all_comment_text.append({
'author': comment.author,
'initials': comment.initials,
'text': main_text,
'detailed_text': detailed_text
})
return all_comment_text
# Extract comment data
comment_data = extract_comment_text(doc)
for comment_info in comment_data:
print(f"Author: {comment_info['author']}")
print(f"Text: {comment_info['text']}")
print("---")Create comments programmatically for automated review processes.
Usage Examples:
import re
def add_spell_check_comments(doc):
"""Add comments for potential spelling issues."""
# Simple spell check simulation
potential_errors = ['teh', 'recieve', 'occured', 'seperate']
for para in doc.paragraphs:
for error in potential_errors:
if error in para.text.lower():
# Find the run containing the error
for run in para.runs:
if error in run.text.lower():
comment = doc.add_comment(
run,
f'Possible spelling error: "{error}"',
author='Spell Checker',
initials='SC'
)
break
def add_length_comments(doc, max_sentence_length=25):
"""Add comments for overly long sentences."""
for para in doc.paragraphs:
sentences = re.split(r'[.!?]+', para.text)
for sentence in sentences:
words = sentence.strip().split()
if len(words) > max_sentence_length:
# Find run containing long sentence
for run in para.runs:
if sentence.strip() in run.text:
comment = doc.add_comment(
run,
f'Long sentence ({len(words)} words). Consider breaking up.',
author='Style Checker',
initials='ST'
)
break
# Apply automated commenting
add_spell_check_comments(doc)
add_length_comments(doc)
def add_consistency_comments(doc, style_guide):
"""Add comments for style guide violations."""
violations = {
'passive_voice': r'\b(was|were|is|are|been)\s+\w+ed\b',
'weak_words': r'\b(very|really|quite|rather)\b',
'contractions': r"\b\w+'\w+\b"
}
for para in doc.paragraphs:
for violation_type, pattern in violations.items():
matches = re.finditer(pattern, para.text, re.IGNORECASE)
for match in matches:
# Find the run containing the match
for run in para.runs:
if match.group() in run.text:
comment = doc.add_comment(
run,
f'Style guide: {violation_type.replace("_", " ").title()}',
author='Style Guide Bot',
initials='SG'
)
break
# Apply style guide checking
style_guide = {} # Style guide configuration
add_consistency_comments(doc, style_guide)# Complete document review workflow
def setup_document_review(doc, reviewers):
"""Set up document for review process."""
# Add review instructions in document
instructions = doc.add_paragraph('REVIEW INSTRUCTIONS:', style='Strong')
doc.add_paragraph('Please add comments to sections that need attention.')
doc.add_paragraph('Use your initials when adding comments.')
doc.add_page_break()
# Track reviewers
reviewer_info = {}
for reviewer in reviewers:
name, initials = reviewer.split('|')
reviewer_info[initials] = name
return reviewer_info
def finalize_review(doc):
"""Generate review summary."""
comments = doc.comments
# Add summary section
doc.add_page_break()
doc.add_heading('Review Summary', level=1)
if len(comments) == 0:
doc.add_paragraph('No comments were added during review.')
return
# Create summary table
summary_table = doc.add_table(rows=1, cols=4)
headers = ['#', 'Author', 'Comment', 'Status']
for i, header in enumerate(headers):
summary_table.cell(0, i).text = header
summary_table.cell(0, i).paragraphs[0].runs[0].bold = True
# Add comment data
for i, comment in enumerate(comments, 1):
row = summary_table.add_row()
row.cells[0].text = str(i)
row.cells[1].text = comment.author or 'Unknown'
row.cells[2].text = comment.text[:100] + ('...' if len(comment.text) > 100 else '')
row.cells[3].text = 'Open'
# Usage
reviewers = ['John Doe|JD', 'Jane Smith|JS', 'Bob Wilson|BW']
reviewer_info = setup_document_review(doc, reviewers)
# ... document review process ...
finalize_review(doc)Install with Tessl CLI
npx tessl i tessl/pypi-python-docx