or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-tools.mdconfiguration.mdcore-analysis.mdindex.mdmodule-loading.mdpyi-parsing.mdpytd-system.md

pyi-parsing.mddocs/

0

# PYI Parsing

1

2

Parser for Python type stub files (.pyi) that converts textual type declarations into PyTD AST representations for analysis and manipulation. The PYI parser enables PyType to work with existing type stub files and generate canonical type declarations.

3

4

## Capabilities

5

6

### String Parsing

7

8

Parse .pyi content from strings into PyTD AST format, providing the core parsing functionality for type stub processing.

9

10

```python { .api }

11

def parse_string(src, filename=None, options=None):

12

"""

13

Parse .pyi string content to PyTD AST.

14

15

Parameters:

16

- src (str): .pyi file content as string

17

- filename (str, optional): Filename for error reporting

18

- options (PyiOptions, optional): Parser configuration options

19

20

Returns:

21

pytd.TypeDeclUnit: PyTD AST representation of the type declarations

22

23

Raises:

24

ParseError: If the .pyi content contains syntax errors

25

"""

26

```

27

28

Example usage:

29

30

```python

31

from pytype.pyi import parser

32

33

pyi_content = '''

34

from typing import List, Optional

35

36

class Calculator:

37

def __init__(self) -> None: ...

38

def add(self, x: int, y: int) -> int: ...

39

def divide(self, x: int, y: int) -> Optional[float]: ...

40

41

def create_calculator() -> Calculator: ...

42

43

PI: float

44

'''

45

46

try:

47

ast = parser.parse_string(pyi_content, filename="calculator.pyi")

48

print(f"Parsed {len(ast.classes)} classes and {len(ast.functions)} functions")

49

except parser.ParseError as e:

50

print(f"Parse error: {e}")

51

```

52

53

### File Parsing

54

55

Parse .pyi files directly from the filesystem with comprehensive error handling and options support.

56

57

```python { .api }

58

def parse_pyi(src, filename, options):

59

"""

60

Parse .pyi file with full option support.

61

62

Parameters:

63

- src (str): .pyi file content

64

- filename (str): Path to .pyi file for error reporting

65

- options (PyiOptions): Complete parser configuration

66

67

Returns:

68

pytd.TypeDeclUnit: Parsed PyTD AST

69

70

Raises:

71

ParseError: If parsing fails due to syntax errors or invalid declarations

72

"""

73

```

74

75

Example usage:

76

77

```python

78

from pytype.pyi import parser

79

80

# Configure parser options

81

options = parser.PyiOptions()

82

options.python_version = (3, 11)

83

84

# Read and parse file

85

with open("mymodule.pyi", "r") as f:

86

content = f.read()

87

88

ast = parser.parse_pyi(content, "mymodule.pyi", options)

89

```

90

91

### Canonical PYI Generation

92

93

Generate canonical .pyi representations from PyTD ASTs, ensuring consistent formatting and optimization of type declarations.

94

95

```python { .api }

96

def canonical_pyi(pyi, multiline_args=False, options=None):

97

"""

98

Generate canonical .pyi string from PyTD AST.

99

100

Parameters:

101

- pyi (pytd.TypeDeclUnit): PyTD AST to convert

102

- multiline_args (bool): Whether to format function arguments across multiple lines

103

- options (PyiOptions, optional): Formatting options

104

105

Returns:

106

str: Canonical .pyi file content with consistent formatting

107

"""

108

```

109

110

Example usage:

111

112

```python

113

from pytype.pyi import parser

114

from pytype import io

115

116

# Generate AST from source code

117

source = '''

118

class DataProcessor:

119

def __init__(self, config=None):

120

self.config = config or {}

121

122

def process(self, data):

123

return [item.strip().upper() for item in data if item]

124

'''

125

126

ast = io.generate_pyi_ast(source)

127

128

# Convert to canonical .pyi format

129

canonical = parser.canonical_pyi(ast, multiline_args=True)

130

print(canonical)

131

```

132

133

### Parser Configuration

134

135

Configure parser behavior through options class for different Python versions and parsing modes.

136

137

```python { .api }

138

class PyiOptions:

139

"""

140

Configuration options for .pyi parsing.

141

142

Controls parser behavior including Python version compatibility,

143

error handling, and output formatting preferences.

144

"""

145

146

def __init__(self):

147

"""Initialize parser options with defaults."""

148

149

python_version: tuple # Target Python version (e.g., (3, 11))

150

strict_import: bool # Strict import checking

151

preserve_union_order: bool # Maintain union type order

152

verify: bool # Verify parsed AST correctness

153

```

154

155

Example configuration:

156

157

```python

158

from pytype.pyi import parser

159

160

# Configure for Python 3.11 with strict checking

161

options = parser.PyiOptions()

162

options.python_version = (3, 11)

163

options.strict_import = True

164

options.verify = True

165

166

# Use in parsing

167

ast = parser.parse_string(pyi_content, options=options)

168

```

169

170

### Error Handling

171

172

Comprehensive error handling for malformed .pyi files and parsing failures.

173

174

```python { .api }

175

class ParseError(Exception):

176

"""

177

Exception raised when .pyi parsing fails.

178

179

Provides detailed information about syntax errors, invalid type

180

declarations, and other parsing failures.

181

"""

182

183

def __init__(self, message, filename=None, lineno=None):

184

"""

185

Initialize parse error.

186

187

Parameters:

188

- message (str): Error description

189

- filename (str, optional): File where error occurred

190

- lineno (int, optional): Line number of error

191

"""

192

```

193

194

Example error handling:

195

196

```python

197

from pytype.pyi import parser

198

199

malformed_pyi = '''

200

class InvalidClass:

201

def bad_method(self, x: InvalidType) -> None: ... # Unknown type

202

def missing_colon(self, x int) -> None: ... # Syntax error

203

'''

204

205

try:

206

ast = parser.parse_string(malformed_pyi, filename="test.pyi")

207

except parser.ParseError as e:

208

print(f"Parse error in {e.filename}:{e.lineno}: {e.message}")

209

```

210

211

### Advanced Parsing Features

212

213

Support for complex type declarations and modern Python typing features.

214

215

```python

216

from pytype.pyi import parser

217

218

# Parse complex type declarations

219

complex_pyi = '''

220

from typing import Generic, TypeVar, Protocol, Literal, Union

221

from collections.abc import Callable, Iterable

222

223

T = TypeVar('T')

224

U = TypeVar('U', bound=str)

225

226

class Container(Generic[T]):

227

def __init__(self, items: list[T]) -> None: ...

228

def get(self, index: int) -> T: ...

229

def map(self, func: Callable[[T], U]) -> Container[U]: ...

230

231

class Processor(Protocol):

232

def process(self, data: str) -> str: ...

233

234

Status = Literal['pending', 'running', 'completed', 'failed']

235

236

def handle_result(

237

result: Union[str, int, None],

238

processor: Processor,

239

status: Status = 'pending'

240

) -> dict[str, str]: ...

241

'''

242

243

ast = parser.parse_string(complex_pyi)

244

print(f"Parsed {len(ast.type_params)} type parameters")

245

print(f"Found {len([c for c in ast.classes if c.template])} generic classes")

246

```

247

248

### Integration with PyType Workflow

249

250

The PYI parser integrates seamlessly with PyType's analysis workflow:

251

252

```python

253

from pytype.pyi import parser

254

from pytype.pytd import pytd_utils

255

from pytype import io, config

256

257

# 1. Parse existing stub file

258

with open("library.pyi", "r") as f:

259

existing_stub = f.read()

260

261

existing_ast = parser.parse_string(existing_stub, filename="library.pyi")

262

263

# 2. Generate new stub from source

264

source_code = open("library.py", "r").read()

265

options = config.Options.create()

266

new_ast = io.generate_pyi_ast(source_code, options=options)

267

268

# 3. Combine ASTs

269

combined_ast = pytd_utils.Concat(existing_ast, new_ast)

270

271

# 4. Generate canonical output

272

canonical_stub = parser.canonical_pyi(combined_ast, multiline_args=True)

273

274

# 5. Write updated stub

275

with open("library_updated.pyi", "w") as f:

276

f.write(canonical_stub)

277

```

278

279

### Performance Considerations

280

281

For large .pyi files or batch processing:

282

283

```python

284

from pytype.pyi import parser

285

import os

286

287

def parse_stub_directory(stub_dir):

288

"""Parse all .pyi files in a directory efficiently."""

289

290

# Reuse options for better performance

291

options = parser.PyiOptions()

292

options.python_version = (3, 11)

293

294

parsed_asts = {}

295

296

for filename in os.listdir(stub_dir):

297

if filename.endswith('.pyi'):

298

filepath = os.path.join(stub_dir, filename)

299

with open(filepath, 'r') as f:

300

content = f.read()

301

302

try:

303

ast = parser.parse_pyi(content, filename, options)

304

parsed_asts[filename] = ast

305

except parser.ParseError as e:

306

print(f"Failed to parse {filename}: {e}")

307

308

return parsed_asts

309

```