or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

chooser.mdcommand-line.mdconfiguration.mddiff-utilities.mdfile-utilities.mdformatters.mdgit-integration.mdindex.mdmain-functions.mdpreprocessors.mdverification.md

index.mddocs/

0

# Darker

1

2

Darker is a Python utility that reformats Python source code files by comparing an old revision of the source tree to a newer revision, applying formatting only to regions that have changed. This selective approach allows teams to adopt code formatters incrementally without disrupting unchanged code.

3

4

## Package Information

5

6

- **Package Name**: darker

7

- **Language**: Python

8

- **Installation**: `pip install darker`

9

- **Optional Dependencies**:

10

- `pip install darker[black]` - for Black formatting

11

- `pip install darker[ruff]` - for Ruff formatting

12

- `pip install darker[pyupgrade]` - for Python syntax upgrading

13

- `pip install darker[flynt]` - for f-string conversion

14

- `pip install darker[isort]` - for import sorting

15

- `pip install darker[color]` - for colored output

16

17

## Core Imports

18

19

```python

20

import darker

21

from darker import main, format_edited_parts

22

from darker.command_line import parse_command_line

23

from darker.config import DarkerConfig, OutputMode

24

```

25

26

For formatter integration:

27

28

```python

29

from darker.formatters import create_formatter, get_formatter_names

30

from darker.formatters.base_formatter import BaseFormatter

31

```

32

33

## Basic Usage

34

35

### Command Line Usage

36

37

```bash

38

# Format only changed regions since last commit

39

darker --check --diff myproject.py

40

41

# Format multiple files with Black and isort

42

darker --black --isort src/

43

44

# Format with Ruff formatter

45

darker --formatter=ruff --check --diff .

46

47

# Format changes since specific revision

48

darker --revision=HEAD~2 --diff src/

49

```

50

51

### Programmatic Usage

52

53

```python

54

from darker import format_edited_parts

55

from darker.config import OutputMode, Exclusions

56

from darkgraylib.git import RevisionRange

57

from pathlib import Path

58

59

# Format edited parts of files

60

results = format_edited_parts(

61

common_root=Path("."),

62

paths={Path("myfile.py")},

63

exclusions=Exclusions(),

64

revrange=RevisionRange.parse_with_common_ancestor("HEAD", ":WORKTREE:"),

65

formatter=create_formatter("black"),

66

report_unmodified=False,

67

workers=1

68

)

69

70

for path, old_content, new_content in results:

71

if old_content != new_content:

72

print(f"Formatted {path}")

73

```

74

75

## Architecture

76

77

Darker is built around several key components:

78

79

- **Main Entry Point**: The `main()` function orchestrates the entire formatting process

80

- **Git Integration**: Compares revisions to identify changed regions using `EditedLinenumsDiffer`

81

- **Formatter Plugin System**: Pluggable formatters (Black, Ruff, Pyupgrade, None) via entry points

82

- **Diff Processing**: Selects which chunks to format based on Git changes

83

- **AST Verification**: Ensures formatting preserves code semantics

84

- **Configuration Management**: Handles command-line args and config file options

85

86

## Capabilities

87

88

### Main Functions

89

90

Core entry points for running darker formatting operations, including the main function that orchestrates the entire process and utility functions for file modification and output.

91

92

```python { .api }

93

def main(argv: List[str] = None) -> int: ...

94

95

def main_with_error_handling() -> int: ...

96

97

def format_edited_parts(

98

root: Path,

99

changed_files: Collection[Path],

100

exclude: Exclusions,

101

revrange: RevisionRange,

102

formatter: BaseFormatter,

103

report_unmodified: bool,

104

workers: int = 1,

105

) -> Generator[Tuple[Path, TextDocument, TextDocument], None, None]: ...

106

```

107

108

[Main Functions](./main-functions.md)

109

110

### Command Line Interface

111

112

Command line argument parsing, configuration management, and option validation for the darker command-line tool.

113

114

```python { .api }

115

def make_argument_parser(require_src: bool) -> ArgumentParser: ...

116

117

def parse_command_line(

118

argv: Optional[List[str]]

119

) -> Tuple[Namespace, DarkerConfig, DarkerConfig]: ...

120

```

121

122

[Command Line Interface](./command-line.md)

123

124

### Configuration Management

125

126

Configuration classes, validation functions, and output mode management for controlling darker's behavior through config files and command-line options.

127

128

```python { .api }

129

class DarkerConfig(BaseConfig, total=False):

130

check: bool

131

diff: bool

132

flynt: bool

133

isort: bool

134

line_length: int

135

lint: list[str]

136

skip_magic_trailing_comma: bool

137

skip_string_normalization: bool

138

target_version: str

139

formatter: str

140

141

class OutputMode:

142

NOTHING = "NOTHING"

143

DIFF = "DIFF"

144

CONTENT = "CONTENT"

145

146

def validate_config_output_mode(

147

diff: bool,

148

stdout: bool

149

) -> OutputMode: ...

150

```

151

152

[Configuration Management](./configuration.md)

153

154

### Formatter System

155

156

Pluggable formatter system supporting multiple code formatters like Black, Ruff, and Pyupgrade through a common interface and entry point system.

157

158

```python { .api }

159

def create_formatter(name: str) -> BaseFormatter: ...

160

161

def get_formatter_names() -> list[str]: ...

162

163

class BaseFormatter(ABC):

164

name: str

165

preserves_ast: bool

166

config_section: str

167

168

def read_config(self, src: tuple[str, ...], args: Namespace) -> None: ...

169

def run(self, content: TextDocument, path_from_cwd: Path) -> TextDocument: ...

170

```

171

172

[Formatter System](./formatters.md)

173

174

### Git Integration

175

176

Git repository interaction, revision comparison, and modified file discovery for determining which files and regions need formatting.

177

178

```python { .api }

179

def git_is_repository(path: Path) -> bool: ...

180

181

def git_get_modified_python_files(

182

paths: Collection[str],

183

revrange: RevisionRange,

184

cwd: Path,

185

) -> Set[str]: ...

186

187

class EditedLinenumsDiffer:

188

def __init__(self, root: Path, revrange: RevisionRange): ...

189

def revision_vs_lines(

190

self, path_in_repo: Path, content: TextDocument, context_lines: int

191

) -> List[int]: ...

192

```

193

194

[Git Integration](./git-integration.md)

195

196

### Pre-processors

197

198

Integration with code pre-processors like isort for import sorting and flynt for f-string conversion, applied before main formatting.

199

200

```python { .api }

201

def apply_isort(

202

content: TextDocument,

203

src: Tuple[str, ...],

204

config: str,

205

) -> TextDocument: ...

206

207

def apply_flynt(

208

content: TextDocument,

209

line_length: int,

210

) -> TextDocument: ...

211

```

212

213

[Pre-processors](./preprocessors.md)

214

215

## Types

216

217

### Core Types

218

219

```python { .api }

220

from typing import Tuple, List, Set, Collection, Generator, Optional

221

from pathlib import Path

222

from darkgraylib.utils import TextDocument

223

from darkgraylib.git import RevisionRange

224

225

# Type aliases

226

ProcessedDocument = Tuple[Path, TextDocument, TextDocument]

227

228

class Exclusions:

229

"""File exclusion patterns for pre-processing steps"""

230

formatter: Set[str]

231

isort: Set[str]

232

flynt: Set[str]

233

234

class TargetVersion(Enum):

235

"""Python version targets for formatting"""

236

PY33 = (3, 3)

237

PY34 = (3, 4)

238

# ... up to PY313

239

```

240

241

### Exception Types

242

243

```python { .api }

244

class DependencyError(Exception):

245

"""Parent class for dependency problems"""

246

247

class IncompatiblePackageError(DependencyError):

248

"""Incompatible version of required package"""

249

250

class MissingPackageError(DependencyError):

251

"""Required/optional package is missing"""

252

253

class NotEquivalentError(Exception):

254

"""Two ASTs being compared are not equivalent"""

255

```