or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/pypi-doc8

Style checker for Sphinx (or other) RST documentation

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/doc8@2.0.x

To install, run

npx @tessl/cli install tessl/pypi-doc8@2.0.0

0

# doc8

1

2

An opinionated style checker for reStructuredText (RST) documentation that helps developers maintain consistent formatting and style in their documentation. doc8 validates RST format, enforces line length limits with intelligent exceptions for URLs and literal blocks, prevents trailing whitespace and tab indentation, ensures Unix newlines, and checks for proper file endings.

3

4

## Package Information

5

6

- **Package Name**: doc8

7

- **Package Type**: pypi

8

- **Language**: Python

9

- **Installation**: `pip install doc8`

10

11

## Core Imports

12

13

```python

14

import doc8

15

```

16

17

For programmatic use:

18

19

```python

20

from doc8 import doc8

21

```

22

23

For accessing version information:

24

25

```python

26

from doc8 import __version__

27

```

28

29

## Basic Usage

30

31

### Command Line Usage

32

33

```bash

34

# Check all documentation files in current directory

35

doc8

36

37

# Check specific directory

38

doc8 my-project/docs

39

40

# Check with specific options

41

doc8 --max-line-length=99 --ignore=D001 docs/

42

43

# Check with configuration file

44

doc8 --config=my-doc8.ini docs/

45

```

46

47

### Programmatic Usage

48

49

```python

50

from doc8 import doc8

51

52

# Basic validation with default settings

53

result = doc8()

54

55

# Custom validation with options

56

result = doc8(

57

paths=['docs/'],

58

max_line_length=99,

59

ignore=['D001'],

60

allow_long_titles=True

61

)

62

63

# Check results

64

print(f"Total errors: {result.total_errors}")

65

print(f"Files checked: {result.files_selected}")

66

print(f"Files ignored: {result.files_ignored}")

67

68

# Get detailed report

69

print(result.report())

70

71

# Access individual errors

72

for check_name, filename, line_num, code, message in result.errors:

73

print(f"{filename}:{line_num}: {code} {message}")

74

```

75

76

## Architecture

77

78

doc8 follows a modular check-based architecture:

79

80

- **Main API**: Core doc8() function and CLI entry point for validation orchestration

81

- **Parser**: File parsing with RST document model creation using docutils

82

- **Checks**: Pluggable validation checks implementing LineCheck or ContentCheck interfaces

83

- **Utils**: File discovery and RST processing utilities

84

- **Configuration**: INI/TOML configuration file support with CLI override capabilities

85

- **Extensions**: Plugin system via stevedore for custom validation checks

86

87

## Capabilities

88

89

### Main Validation API

90

91

Primary interface for doc8 validation functionality, supporting both programmatic and command-line usage with extensive configuration options.

92

93

```python { .api }

94

def doc8(args=None, **kwargs):

95

"""

96

Execute doc8 validation on documentation files.

97

98

Args:

99

args (dict, optional): Configuration arguments dictionary

100

**kwargs: Configuration options as keyword arguments

101

102

Returns:

103

Result: Validation results with error details and statistics

104

"""

105

```

106

107

```python { .api }

108

def main():

109

"""

110

Command-line interface entry point for doc8.

111

112

Returns:

113

int: Exit code (0 for success, 1 for errors)

114

"""

115

```

116

117

### Configuration Management

118

119

Functions for loading and managing doc8 configuration from files and command-line arguments.

120

121

```python { .api }

122

def get_defaults():

123

"""

124

Get default configuration settings.

125

126

Returns:

127

dict: Default configuration dictionary

128

"""

129

```

130

131

```python { .api }

132

def extract_config(args):

133

"""

134

Extract configuration from INI or TOML files.

135

136

Args:

137

args (dict): Command-line arguments containing config file paths

138

139

Returns:

140

dict: Configuration dictionary parsed from files

141

"""

142

```

143

144

```python { .api }

145

def from_ini(fp):

146

"""

147

Parse doc8 configuration from INI file.

148

149

Args:

150

fp (str): File path to INI configuration file

151

152

Returns:

153

dict: Configuration dictionary

154

"""

155

```

156

157

```python { .api }

158

def from_toml(fp):

159

"""

160

Parse doc8 configuration from TOML file.

161

162

Args:

163

fp (str): File path to TOML configuration file

164

165

Returns:

166

dict: Configuration dictionary

167

"""

168

```

169

170

### File Processing

171

172

Functions for discovering, scanning, and parsing documentation files for validation.

173

174

```python { .api }

175

def scan(cfg):

176

"""

177

Scan directories for documentation files to validate.

178

179

Args:

180

cfg (dict): Configuration dictionary with paths, extensions, and ignore patterns

181

182

Returns:

183

tuple: (list of ParsedFile objects, count of ignored files)

184

"""

185

```

186

187

```python { .api }

188

def validate(cfg, files, result=None):

189

"""

190

Run validation checks on parsed documentation files.

191

192

Args:

193

cfg (dict): Configuration dictionary

194

files (list): List of ParsedFile objects to validate

195

result (Result, optional): Result object to populate with errors

196

197

Returns:

198

dict: Error counts by check name

199

"""

200

```

201

202

```python { .api }

203

def fetch_checks(cfg):

204

"""

205

Load built-in and extension validation checks.

206

207

Args:

208

cfg (dict): Configuration dictionary

209

210

Returns:

211

list: List of check objects implementing validation interfaces

212

"""

213

```

214

215

### File Parsing

216

217

Classes and functions for parsing documentation files and creating structured representations.

218

219

```python { .api }

220

def parse(filename, encoding=None, default_extension=""):

221

"""

222

Parse a documentation file into a structured representation.

223

224

Args:

225

filename (str): Path to file to parse

226

encoding (str, optional): Text encoding for file reading

227

default_extension (str, optional): Extension to use if file has none

228

229

Returns:

230

ParsedFile: Parsed file object with content and metadata

231

"""

232

```

233

234

```python { .api }

235

class ParsedFile:

236

"""

237

Parsed documentation file with RST processing capabilities.

238

239

Attributes:

240

FALLBACK_ENCODING (str): Default encoding when none specified ("utf-8")

241

"""

242

243

def __init__(self, filename, encoding=None, default_extension=""):

244

"""

245

Initialize parsed file.

246

247

Args:

248

filename (str): Path to the file

249

encoding (str, optional): Text encoding

250

default_extension (str, optional): Default extension if none present

251

"""

252

253

@property

254

def errors(self):

255

"""

256

RST parsing errors from restructuredtext_lint.

257

258

Returns:

259

list: List of parsing error objects

260

"""

261

262

@property

263

def document(self):

264

"""

265

Docutils document object for RST content.

266

267

Returns:

268

docutils.nodes.document: Parsed RST document

269

"""

270

271

@property

272

def lines(self):

273

"""

274

Raw byte lines from file.

275

276

Returns:

277

list: List of byte strings representing file lines

278

"""

279

280

@property

281

def extension(self):

282

"""

283

File extension.

284

285

Returns:

286

str: File extension including dot (e.g., ".rst")

287

"""

288

289

@property

290

def filename(self):

291

"""

292

File path.

293

294

Returns:

295

str: Absolute path to the file

296

"""

297

298

@property

299

def encoding(self):

300

"""

301

Text encoding used for file.

302

303

Returns:

304

str: Character encoding name

305

"""

306

307

@property

308

def raw_contents(self):

309

"""

310

Raw file contents as bytes.

311

312

Returns:

313

bytes: File contents

314

"""

315

316

@property

317

def contents(self):

318

"""

319

Decoded file contents as string.

320

321

Returns:

322

str: File contents as text

323

"""

324

325

def lines_iter(self, remove_trailing_newline=True):

326

"""

327

Iterate over decoded text lines.

328

329

Args:

330

remove_trailing_newline (bool): Whether to strip trailing newlines

331

332

Yields:

333

str: Text lines from file

334

"""

335

```

336

337

### Validation Checks

338

339

Base classes and concrete implementations for documentation validation checks.

340

341

```python { .api }

342

class ContentCheck:

343

"""

344

Abstract base class for checks that operate on entire file content.

345

"""

346

347

def __init__(self, cfg):

348

"""

349

Initialize check with configuration.

350

351

Args:

352

cfg (dict): Configuration dictionary

353

"""

354

355

def report_iter(self, parsed_file):

356

"""

357

Generate validation results for file content.

358

359

Args:

360

parsed_file (ParsedFile): File to validate

361

362

Yields:

363

tuple: (line_number, error_code, message) for each error found

364

"""

365

```

366

367

```python { .api }

368

class LineCheck:

369

"""

370

Abstract base class for checks that operate line-by-line.

371

"""

372

373

def __init__(self, cfg):

374

"""

375

Initialize check with configuration.

376

377

Args:

378

cfg (dict): Configuration dictionary

379

"""

380

381

def report_iter(self, line):

382

"""

383

Generate validation results for a single line.

384

385

Args:

386

line (str): Text line to validate

387

388

Yields:

389

tuple: (error_code, message) for each error found

390

"""

391

```

392

393

```python { .api }

394

class CheckTrailingWhitespace(LineCheck):

395

"""

396

Check for trailing whitespace in lines.

397

398

Attributes:

399

REPORTS (frozenset): Error codes reported (["D002"])

400

"""

401

```

402

403

```python { .api }

404

class CheckIndentationNoTab(LineCheck):

405

"""

406

Check for tab characters in indentation.

407

408

Attributes:

409

REPORTS (frozenset): Error codes reported (["D003"])

410

"""

411

```

412

413

```python { .api }

414

class CheckCarriageReturn(ContentCheck):

415

"""

416

Check for carriage return characters in file content.

417

418

Attributes:

419

REPORTS (frozenset): Error codes reported (["D004"])

420

"""

421

```

422

423

```python { .api }

424

class CheckNewlineEndOfFile(ContentCheck):

425

"""

426

Check that file ends with a newline character.

427

428

Attributes:

429

REPORTS (frozenset): Error codes reported (["D005"])

430

"""

431

```

432

433

```python { .api }

434

class CheckValidity(ContentCheck):

435

"""

436

Check RST syntax validity using docutils.

437

438

Attributes:

439

REPORTS (frozenset): Error codes reported (["D000"])

440

EXT_MATCHER (re.Pattern): Regex matching .rst files

441

WARN_LEVELS (frozenset): Docutils warning levels to report

442

SPHINX_IGNORES_REGEX (list): Patterns to ignore in Sphinx mode

443

"""

444

```

445

446

```python { .api }

447

class CheckMaxLineLength(ContentCheck):

448

"""

449

Check line length limits with RST-aware exceptions.

450

451

Attributes:

452

REPORTS (frozenset): Error codes reported (["D001"])

453

"""

454

```

455

456

### Results and Reporting

457

458

Classes for handling validation results and generating reports.

459

460

```python { .api }

461

class Result:

462

"""

463

Container for doc8 validation results and statistics.

464

"""

465

466

def __init__(self):

467

"""Initialize empty result."""

468

469

@property

470

def total_errors(self):

471

"""

472

Total number of errors found.

473

474

Returns:

475

int: Count of all errors

476

"""

477

478

def error(self, check_name, filename, line_num, code, message):

479

"""

480

Record a validation error.

481

482

Args:

483

check_name (str): Name of check that found error

484

filename (str): File path where error occurred

485

line_num (int): Line number of error

486

code (str): Error code (D000-D005)

487

message (str): Human-readable error description

488

"""

489

490

def finish(self, files_selected, files_ignored, error_counts):

491

"""

492

Finalize results with file and error statistics.

493

494

Args:

495

files_selected (int): Number of files processed

496

files_ignored (int): Number of files ignored

497

error_counts (dict): Error counts by check name

498

"""

499

500

def report(self):

501

"""

502

Generate human-readable validation report.

503

504

Returns:

505

str: Formatted report with error details and statistics

506

"""

507

```

508

509

### Utility Functions

510

511

Helper functions for file discovery, RST processing, and configuration parsing.

512

513

```python { .api }

514

def find_files(paths, extensions, ignored_paths):

515

"""

516

Recursively find documentation files matching extensions.

517

518

Args:

519

paths (list): Root paths to search

520

extensions (set): File extensions to include

521

ignored_paths (list): Paths to ignore (supports globs)

522

523

Yields:

524

tuple: (filepath, is_ignorable) for each matching file

525

"""

526

```

527

528

```python { .api }

529

def filtered_traverse(document, filter_func):

530

"""

531

Traverse docutils document tree with filtering.

532

533

Args:

534

document (docutils.nodes.document): RST document to traverse

535

filter_func (callable): Function to filter nodes

536

537

Yields:

538

docutils.nodes.Node: Filtered document nodes

539

"""

540

```

541

542

```python { .api }

543

def contains_url(line):

544

"""

545

Check if text line contains HTTP or HTTPS URLs.

546

547

Args:

548

line (str): Text line to check

549

550

Returns:

551

bool: True if line contains URLs

552

"""

553

```

554

555

```python { .api }

556

def has_any_node_type(node, node_types):

557

"""

558

Check if node or its ancestors match given types.

559

560

Args:

561

node (docutils.nodes.Node): Node to check

562

node_types (tuple): Node types to match against

563

564

Returns:

565

bool: True if node or ancestor matches types

566

"""

567

```

568

569

```python { .api }

570

def split_set_type(text, delimiter=","):

571

"""

572

Parse delimited text into set of values.

573

574

Args:

575

text (str): Delimited string to parse

576

delimiter (str): Delimiter character

577

578

Returns:

579

set: Set of parsed string values

580

"""

581

```

582

583

```python { .api }

584

def merge_sets(sets):

585

"""

586

Merge multiple sets into single set.

587

588

Args:

589

sets (iterable): Sets to merge

590

591

Returns:

592

set: Combined set containing all values

593

"""

594

```

595

596

```python { .api }

597

def parse_ignore_path_errors(entries):

598

"""

599

Parse path-specific error ignore patterns.

600

601

Args:

602

entries (list): List of "path;error_code;error_code" entries

603

604

Returns:

605

dict: Mapping of paths to sets of ignored error codes

606

"""

607

```

608

609

```python { .api }

610

def setup_logging(verbose):

611

"""

612

Configure logging output based on verbosity setting.

613

614

Args:

615

verbose (bool): Enable verbose logging output

616

"""

617

```

618

619

## Types

620

621

### Configuration Options

622

623

```python { .api }

624

# Configuration dictionary keys and their types

625

ConfigDict = {

626

"paths": list, # Paths to scan for files

627

"config": list, # Configuration file paths

628

"allow_long_titles": bool, # Allow long section titles

629

"ignore": set, # Error codes to ignore

630

"sphinx": bool, # Enable Sphinx-specific ignores

631

"ignore_path": list, # Paths to ignore (globs supported)

632

"ignore_path_errors": dict, # Path-specific error ignores

633

"default_extension": str, # Default file extension

634

"file_encoding": str, # Text encoding for files

635

"max_line_length": int, # Maximum line length

636

"extension": list, # File extensions to check

637

"quiet": bool, # Suppress non-error output

638

"verbose": bool, # Enable verbose output

639

"version": bool, # Show version and exit

640

}

641

```

642

643

### Error Codes

644

645

```python { .api }

646

# Validation error codes

647

ERROR_CODES = {

648

"D000": "Invalid RST format",

649

"D001": "Line too long",

650

"D002": "Trailing whitespace",

651

"D003": "Tab indentation",

652

"D004": "Carriage returns (non-Unix newlines)",

653

"D005": "No newline at end of file",

654

}

655

```

656

657

### Module Constants

658

659

```python { .api }

660

# Default file extensions to check

661

FILE_PATTERNS = [".rst", ".txt"]

662

663

# Default maximum line length

664

MAX_LINE_LENGTH = 79

665

666

# Configuration file search order

667

CONFIG_FILENAMES = [

668

"doc8.ini",

669

".config/doc8.ini",

670

"tox.ini",

671

"pep8.ini",

672

"setup.cfg",

673

"pyproject.toml",

674

]

675

```

676

677

## Configuration

678

679

### Configuration Files

680

681

doc8 automatically searches for configuration in these files:

682

683

- `doc8.ini`

684

- `.config/doc8.ini`

685

- `tox.ini`

686

- `pep8.ini`

687

- `setup.cfg`

688

- `pyproject.toml`

689

690

### INI Format Example

691

692

```ini

693

[doc8]

694

max-line-length = 99

695

ignore = D001,D002

696

ignore-path = build/,temp/

697

ignore-path-errors = docs/legacy.rst;D001;D002

698

allow-long-titles = true

699

verbose = false

700

sphinx = true

701

file-encoding = utf-8

702

default-extension = .rst

703

extensions = .rst,.txt

704

```

705

706

### TOML Format Example

707

708

```toml

709

[tool.doc8]

710

max-line-length = 99

711

ignore = ["D001", "D002"]

712

ignore-path = ["build/", "temp/"]

713

ignore-path-errors = ["docs/legacy.rst;D001;D002"]

714

allow-long-titles = true

715

verbose = false

716

sphinx = true

717

file-encoding = "utf-8"

718

default-extension = ".rst"

719

extensions = [".rst", ".txt"]

720

```

721

722

## Extension System

723

724

doc8 supports custom validation checks through the stevedore plugin system:

725

726

### Plugin Namespace

727

728

- **Entry Point**: `doc8.extension.check`

729

- **Interface**: Checks must inherit from `ContentCheck` or `LineCheck`

730

- **Loading**: Extensions are automatically discovered and loaded

731

732

### Custom Check Example

733

734

```python

735

from doc8.checks import LineCheck

736

737

class MyCustomCheck(LineCheck):

738

REPORTS = frozenset(["C001"])

739

740

def __init__(self, cfg):

741

super().__init__(cfg)

742

743

def report_iter(self, line):

744

if "bad_pattern" in line:

745

yield ("C001", "Found bad pattern")

746

747

# Register in setup.py or pyproject.toml:

748

# [project.entry-points."doc8.extension.check"]

749

# my_check = "mypackage.checks:MyCustomCheck"

750

```