CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-docx

Create, read, and update Microsoft Word .docx files.

Pending
Overview
Eval results
Files

comments.mddocs/

Comments

Document commenting system for adding and managing comments anchored to specific text ranges. Provides collaborative features for document review and annotation.

Capabilities

Comment Management

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}")

Creating Comments

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')

Comment Properties

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}")

Advanced Comment Usage

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 = data

Comment Analysis and Reporting

Analyze 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("---")

Programmatic Comment Creation

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)

Usage Patterns

Document Review Workflow

# 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

docs

comments.md

document-operations.md

images-shapes.md

index.md

sections-layout.md

styles-formatting.md

tables.md

text-paragraphs.md

tile.json