or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analysis-runner.mdconfiguration.mdexceptions.mdfile-finding.mdformatters.mdindex.mdmessages.mdprofiles.mdtools.md

file-finding.mddocs/

0

# File Finding

1

2

File and module discovery system that identifies Python code to be analyzed. The FileFinder class handles discovery of Python files, modules, and packages while respecting exclusion filters.

3

4

## Capabilities

5

6

### FileFinder Class

7

8

Discovers files and modules to be analyzed by static analysis tools.

9

10

```python { .api }

11

class FileFinder:

12

def __init__(self, *provided_paths: Path,

13

exclusion_filters: Optional[Iterable[Callable[[Path], bool]]] = None) -> None

14

```

15

16

Creates a new FileFinder for discovering Python code.

17

18

**Parameters:**

19

- `*provided_paths`: Path - One or more paths to search (files or directories)

20

- `exclusion_filters`: Optional[Iterable[Callable[[Path], bool]]] - List of filter functions that return True for paths to exclude

21

22

**Built-in Exclusions:**

23

The FileFinder automatically excludes:

24

- Directories: `.git`, `.tox`, `.mypy_cache`, `.pytest_cache`, `.venv`, `__pycache__`, `node_modules`

25

- Virtual environments (detected using heuristics)

26

27

### File Discovery Properties and Methods

28

29

```python { .api }

30

@property

31

def files(self) -> set[Path]

32

```

33

34

Lists every individual file found from the provided paths.

35

36

**Returns:**

37

- `set[Path]` - Set of Path objects for all discovered files

38

39

This property recursively discovers all files in the provided directories, applying exclusion filters.

40

41

```python { .api }

42

@property

43

def python_modules(self) -> list[Path]

44

```

45

46

Lists every Python module file found in the provided paths.

47

48

**Returns:**

49

- `list[Path]` - List of Path objects for Python module files (`.py` files)

50

51

Returns individual Python files that pass the `is_python_module` test.

52

53

```python { .api }

54

@property

55

def python_packages(self) -> list[Path]

56

```

57

58

Lists every directory that is a Python package (contains `__init__.py`).

59

60

**Returns:**

61

- `list[Path]` - List of Path objects for package directories

62

63

```python { .api }

64

@property

65

def directories(self) -> set[Path]

66

```

67

68

Lists every directory found from the provided paths.

69

70

**Returns:**

71

- `set[Path]` - Set of Path objects for all discovered directories

72

73

```python { .api }

74

def is_excluded(self, path: Path) -> bool

75

```

76

77

Checks if a path would be excluded by the configured filters.

78

79

**Parameters:**

80

- `path`: Path - The path to check

81

82

**Returns:**

83

- `bool` - True if the path should be excluded

84

85

### Python Path Management

86

87

```python { .api }

88

def make_syspath(self) -> list[Path]

89

```

90

91

Creates a list of paths suitable for adding to Python's sys.path.

92

93

**Returns:**

94

- `list[Path]` - List of directory paths that should be added to sys.path for proper module resolution

95

96

This method analyzes the provided paths and determines the appropriate parent directories that should be in sys.path to ensure proper module imports during analysis.

97

98

## Usage Examples

99

100

### Basic File Discovery

101

102

```python

103

from pathlib import Path

104

from prospector.finder import FileFinder

105

106

# Discover files in current directory

107

finder = FileFinder(Path("."))

108

109

# Get all Python modules

110

modules = finder.python_modules

111

print(f"Found {len(modules)} Python modules:")

112

for module in modules:

113

print(f" {module}")

114

115

# Get all packages

116

packages = finder.python_packages

117

print(f"Found {len(packages)} packages:")

118

for package in packages:

119

print(f" {package}")

120

```

121

122

### Multiple Path Discovery

123

124

```python

125

from pathlib import Path

126

from prospector.finder import FileFinder

127

128

# Analyze multiple paths

129

paths = [Path("src"), Path("tests"), Path("scripts")]

130

finder = FileFinder(*paths)

131

132

# Iterate over all modules

133

for module_path in finder.python_modules:

134

print(f"Module: {module_path}")

135

136

# Get syspath entries

137

syspath_entries = finder.make_syspath()

138

print(f"Sys.path entries needed: {syspath_entries}")

139

```

140

141

### Custom Exclusion Filters

142

143

```python

144

from pathlib import Path

145

from prospector.finder import FileFinder

146

import re

147

148

# Create custom exclusion filters

149

def exclude_test_files(path: Path) -> bool:

150

"""Exclude test files"""

151

return path.name.startswith("test_") or path.name.endswith("_test.py")

152

153

def exclude_migration_files(path: Path) -> bool:

154

"""Exclude Django migration files"""

155

return "migrations" in path.parts and path.suffix == ".py"

156

157

# Create finder with custom filters

158

finder = FileFinder(

159

Path("src"),

160

exclusion_filters=[exclude_test_files, exclude_migration_files]

161

)

162

163

# Only non-test, non-migration files will be found

164

modules = finder.python_modules

165

print(f"Found {len(modules)} modules (excluding tests and migrations)")

166

```

167

168

### Working with Configuration

169

170

```python

171

from pathlib import Path

172

from prospector.finder import FileFinder

173

from prospector.config import ProspectorConfig

174

175

# Use with ProspectorConfig exclusion filter

176

config = ProspectorConfig()

177

paths = [Path(".")]

178

179

# Create finder with config's exclusion filters

180

finder = FileFinder(*paths, exclusion_filters=[config.make_exclusion_filter()])

181

182

# Get modules that pass all filters

183

modules = finder.python_modules

184

185

# Check what would be included vs excluded

186

print("Included modules:")

187

for module in finder.python_modules:

188

print(f" {module}")

189

190

print("\nAll files (use files property for complete file list):")

191

for file_path in finder.files:

192

print(f" {file_path}")

193

```

194

195

### Specific File Analysis

196

197

```python

198

from pathlib import Path

199

from prospector.finder import FileFinder

200

201

# Analyze specific files

202

specific_files = [

203

Path("src/main.py"),

204

Path("src/utils.py"),

205

Path("tests/test_main.py")

206

]

207

208

finder = FileFinder(*specific_files)

209

210

# When providing specific files, they are all considered modules

211

modules = finder.python_modules

212

print(f"Analyzing {len(modules)} specific files:")

213

for module in modules:

214

print(f" {module}")

215

216

# Syspath still works with specific files

217

syspath = finder.make_syspath()

218

print(f"Syspath entries: {syspath}")

219

```

220

221

### Error Handling

222

223

```python

224

from pathlib import Path

225

from prospector.finder import FileFinder

226

227

try:

228

# This will raise FileNotFoundError if path doesn't exist

229

finder = FileFinder(Path("nonexistent/path"))

230

except FileNotFoundError as e:

231

print(f"Path not found: {e}")

232

233

# Safer approach - check existence first

234

paths_to_check = [Path("src"), Path("lib"), Path("scripts")]

235

valid_paths = [p for p in paths_to_check if p.exists()]

236

237

if valid_paths:

238

finder = FileFinder(*valid_paths)

239

modules = finder.python_modules

240

print(f"Found {len(modules)} modules in {len(valid_paths)} valid paths")

241

else:

242

print("No valid paths found")

243

```

244

245

### Integration with Tools

246

247

```python

248

from pathlib import Path

249

from prospector.finder import FileFinder

250

from prospector.config import ProspectorConfig

251

252

# This is how FileFinder is typically used within Prospector

253

config = ProspectorConfig()

254

255

# Create finder with config's paths and exclusion filters

256

paths = [Path(p) for p in config.paths]

257

finder = FileFinder(*paths, exclusion_filters=[config.make_exclusion_filter()])

258

259

# Tools use the finder to discover files to analyze

260

tools = config.get_tools(finder)

261

262

# Each tool gets the same FileFinder instance

263

for tool in tools:

264

print(f"Running {tool.__class__.__name__}")

265

messages = tool.run(finder)

266

print(f" Found {len(messages)} issues")

267

268

# Tools can access different file views:

269

print(f"Python modules: {len(finder.python_modules)}")

270

print(f"Python packages: {len(finder.python_packages)}")

271

print(f"All files: {len(finder.files)}")

272

print(f"Directories: {len(finder.directories)}")

273

```