or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdfile-filtering.mdfile-watching.mdindex.mdprocess-management.md

file-watching.mddocs/

0

# File Watching

1

2

Core file watching functionality providing both synchronous and asynchronous APIs for monitoring file system changes. Built on the high-performance Rust notify library with extensive configuration options for debouncing, filtering, and event handling.

3

4

## Capabilities

5

6

### Synchronous File Watching

7

8

Watch filesystem paths and yield sets of file changes as they occur. Supports multiple paths, recursive watching, and configurable debouncing to group rapid changes.

9

10

```python { .api }

11

def watch(

12

*paths: Union[Path, str],

13

watch_filter: Optional[Callable[[Change, str], bool]] = DefaultFilter(),

14

debounce: int = 1_600,

15

step: int = 50,

16

stop_event: Optional[AbstractEvent] = None,

17

rust_timeout: int = 5_000,

18

yield_on_timeout: bool = False,

19

debug: Optional[bool] = None,

20

raise_interrupt: bool = True,

21

force_polling: Optional[bool] = None,

22

poll_delay_ms: int = 300,

23

recursive: bool = True,

24

ignore_permission_denied: Optional[bool] = None,

25

) -> Generator[Set[FileChange], None, None]:

26

"""

27

Watch one or more paths and yield a set of changes whenever files change.

28

29

Parameters:

30

- *paths: Filesystem paths to watch (files or directories)

31

- watch_filter: Callable to filter changes, defaults to DefaultFilter()

32

- debounce: Maximum time in ms to group changes before yielding

33

- step: Time in ms to wait for new changes if at least one detected

34

- stop_event: Event to stop watching (any object with is_set() method)

35

- rust_timeout: Maximum time in ms to wait for changes in rust code

36

- yield_on_timeout: If True, yield empty set on timeout

37

- debug: Print filesystem changes to stdout (uses WATCHFILES_DEBUG env var if None)

38

- raise_interrupt: Whether to re-raise KeyboardInterrupt or suppress and stop

39

- force_polling: Force use of polling instead of native notifications

40

- poll_delay_ms: Delay between polls when force_polling=True

41

- recursive: Watch subdirectories recursively

42

- ignore_permission_denied: Ignore permission denied errors

43

44

Yields:

45

Set[FileChange]: Set of (Change, path) tuples representing file changes

46

47

Raises:

48

KeyboardInterrupt: If raise_interrupt=True and Ctrl+C pressed

49

"""

50

```

51

52

**Usage Examples:**

53

54

```python

55

from watchfiles import watch, Change

56

57

# Basic usage - watch current directory

58

for changes in watch('.'):

59

print(f'Changes detected: {changes}')

60

61

# Watch multiple paths with custom filter

62

from watchfiles import PythonFilter

63

64

for changes in watch('./src', './tests', watch_filter=PythonFilter()):

65

for change_type, path in changes:

66

if change_type == Change.added:

67

print(f'New file: {path}')

68

elif change_type == Change.modified:

69

print(f'Modified: {path}')

70

elif change_type == Change.deleted:

71

print(f'Deleted: {path}')

72

73

# Watch with stop event

74

import threading

75

76

stop_event = threading.Event()

77

threading.Timer(10.0, stop_event.set).start() # Stop after 10 seconds

78

79

for changes in watch('./src', stop_event=stop_event):

80

print(f'Changes: {changes}')

81

```

82

83

### Asynchronous File Watching

84

85

Async equivalent of the synchronous watch function, using threads internally with anyio for cross-platform async support.

86

87

```python { .api }

88

async def awatch(

89

*paths: Union[Path, str],

90

watch_filter: Optional[Callable[[Change, str], bool]] = DefaultFilter(),

91

debounce: int = 1_600,

92

step: int = 50,

93

stop_event: Optional[AnyEvent] = None,

94

rust_timeout: Optional[int] = None,

95

yield_on_timeout: bool = False,

96

debug: Optional[bool] = None,

97

raise_interrupt: Optional[bool] = None,

98

force_polling: Optional[bool] = None,

99

poll_delay_ms: int = 300,

100

recursive: bool = True,

101

ignore_permission_denied: Optional[bool] = None,

102

) -> AsyncGenerator[Set[FileChange], None]:

103

"""

104

Asynchronous version of watch() using threads.

105

106

Parameters:

107

Same as watch() except:

108

- stop_event: anyio.Event, asyncio.Event, or trio.Event

109

- rust_timeout: None means 1000ms on Windows, 5000ms elsewhere

110

- raise_interrupt: Deprecated, KeyboardInterrupt handled by event loop

111

112

Yields:

113

Set[FileChange]: Set of (Change, path) tuples representing file changes

114

115

Note:

116

KeyboardInterrupt cannot be suppressed and must be caught at the

117

asyncio.run() level or equivalent.

118

"""

119

```

120

121

**Usage Examples:**

122

123

```python

124

import asyncio

125

from watchfiles import awatch

126

127

async def monitor_files():

128

async for changes in awatch('./src', './tests'):

129

print(f'Async changes: {changes}')

130

131

# Run with proper KeyboardInterrupt handling

132

try:

133

asyncio.run(monitor_files())

134

except KeyboardInterrupt:

135

print('Monitoring stopped')

136

137

# With stop event

138

async def monitor_with_timeout():

139

stop_event = asyncio.Event()

140

141

# Stop after 10 seconds

142

async def stop_after_delay():

143

await asyncio.sleep(10)

144

stop_event.set()

145

146

stop_task = asyncio.create_task(stop_after_delay())

147

148

async for changes in awatch('./src', stop_event=stop_event):

149

print(f'Changes: {changes}')

150

151

await stop_task

152

153

asyncio.run(monitor_with_timeout())

154

```

155

156

### Force Polling Configuration

157

158

watchfiles automatically determines when to use polling vs native file system notifications, but this can be controlled manually:

159

160

**Automatic Force Polling Logic:**

161

- If `WATCHFILES_FORCE_POLLING` environment variable exists and is not empty:

162

- If value is `false`, `disable`, or `disabled`: force polling disabled

163

- Otherwise: force polling enabled

164

- Otherwise: force polling enabled only on WSL (Windows Subsystem for Linux)

165

166

**Polling Delay Configuration:**

167

- If `WATCHFILES_POLL_DELAY_MS` environment variable exists and is numeric: use that value

168

- Otherwise: use the `poll_delay_ms` parameter value (default 300ms)

169

170

**Example:**

171

172

```python

173

# Force polling with custom delay

174

for changes in watch('./src', force_polling=True, poll_delay_ms=100):

175

print(f'Polled changes: {changes}')

176

```

177

178

## Types

179

180

```python { .api }

181

# Type definitions used in file watching

182

FileChange = Tuple[Change, str]

183

184

class AbstractEvent(Protocol):

185

def is_set(self) -> bool: ...

186

187

# Union type for async events (TYPE_CHECKING only)

188

AnyEvent = Union[anyio.Event, asyncio.Event, trio.Event]

189

```