Change:
Issue Type: <bBug</b<!-- Please fill in all XXX markers --Expected - file watcher to properly determine if is a file or directory and to monitor it accordingly. Actual: [2022-05-31 17:41:13.382] [renderer1] [error] [File Watcher (parcel)] Unexpected error: Not a directory (EUNKNOWN) (path: c:PROGRAMSpythonpython) [2022-05-31 17:41:13.387] [renderer1] [error] [File Watcher (universal)] restarting watcher after error: Not a directory Python 3.10.4 - latest embeddable version from official website Add python to %PATH% env var and start vs code Code - create python project file watcher thinks is a directory <!-- After creating the issue on GitHub, you can add screenshots and GIFs of what is happening. Consider tools like , or for GIF creation. --<!-- NOTE: Everything below except Python output panel is auto-generated; no editing required. Please do provide Python output panel. --- Python version (& distribution if applicable, e.g. Anaconda): 3.10.4 Type of virtual environment used (e.g. conda, venv, virtualenv, etc.): System Value of the setting: Default <details<summaryOutput for <codePython</codein the <codeOutput</codepanel (<codeView</code→<codeOutput</code, change the drop-down the upper-right of the <codeOutput</codepanel to <codePython</code) </summary<p</p</details<details<summaryUser Settings</summary<p</p</detailsExtension version: 2022.6.3 VS Code version: Code 1.67.2 (, 2022-05-17T18:15:52.058Z) OS version: WindowsNT x64 10.0. Restricted Mode: No <details<summarySystem Info</summary </details<details<summaryA/B Experiments</summary</details<!-- generated by issue reporter --
Moving this to VS Code which provides the watcher APIs the python extension depends on. This should probably be filed on with repro details.
why is Python extension watching a zip file recursively? It should be easy to fix from your extension no? On our end I could throw an error when you try to watch a file recursively...
might have more details on the exact patterns that we use to search. As far as I know, on windows we restrict the pattern to when searching recursively.
To clarify: if any of the patterns include a or a we enable recursive watching, otherwise it will be flat.
I have a change prepared that changes a recursive watcher request to a flat watcher request if the path is a file and not a folder. But since this will only go out for June, I suggest that the Python extension pushes a band-aid fix for now, because otherwise all file watching will stop.
We watch for the following patterns in the workspace: "" "" "" We've not changed this pattern since forever, I'm not sure how is being watched given it does not conform to the pattern. To me it looks like something has changed in the watcher.
It could be the other plugin then - I noticed that disabling either python only or pylance only always stops the error (if that is the case then I assume disabling python simply breaks pylance too - hence no error when python is disabled) that or - any other python dependent plugin Installed plugins (python related - I assumed jupyter ones are not active on console python project) NB! there may be other plugins without Py in their names that rely on python - ex. who know if vscode-solution-explorer is python dependent or not I also noticed (probably unrelated error) in the Output section pylint is not a listed/installed extension so I guess I'm into this category so it could be any of these: python - pylance - pylint(bundled) P.S. Probably also unrelated but... Recent Windows versions (10, 11) show zip files as folders in Windows Explorer (maybe in certain APIs too) so if file watcher hits first (searching for using rule: "*") it may try to descend into that "folder" - what are the chances?
There's also this NB! Although corrected ... (original: , real: ) it still tries to watch original (non corrected) path instead of (see right above it) This folder is a JUNCTION to or whatever version the current python project uses. Junction is created with and is a hard link to with HTH
yeah that sounds ok to me, if you are setting up the file watcher with a glob pattern like that. The issue would only manifest itself if you have code like this: Explaining above: this asks VSCode to install a watcher on the provided path since the path is outside any opened workspace (most likely), we create a new file watcher since the glob pattern is ``, we create a recursive watcher (parcel) not a flat watcher () this will cause an exception from parcel that takes down all file watchers
If disabling Pylance always stops the error I would think the watcher is being set up by Pylance instead. Please open an issue at referencing this.
I can confirm it is pylance - showing only important lines below
Verification: setup a watcher from an extension like where you watch a file with a recursive pattern verify that changes to the file path are resulting in an event for your listener To diagnose you can run with and filter down the console in devtools to , it will print detailed information about file watching. When you see "parcel", a recursive watcher is setup and when you see "", a flat watcher is setup.
<!-- AUTHORVERIFICATIONREQUEST --This bug has been fixed in the latest release of ! you can help us out by commenting if things are now working as expected. If things still don't seem right, please ensure you're on version of Insiders (today's or later - you can use in the command palette to check), and leave a comment letting us know what isn't working as expected. Happy Coding!
Cannot verify since the bug was already fixed in the extension (in official release channel) and issue no longer exists. see "This issue has been fixed in version 2022.6.10, which we've just released." Bug Fix: Fix file watcher behavior with ZIP files ()
You can verify it by installing an older version of the extension which has the bug, please try this: You can follow the prompts from "Extensions: Install Specific Version of Extension..." in the command palette: <img width="625" alt="image" src="https://user-"

Discussion:
return coalescer.coalesce(); } <ins> export function normalizeWatcherPattern(path: string, pattern: string | IRelativePattern): string | IRelativePattern { // Patterns are always matched on the full absolute path // of the event. As such, if the pattern is not absolute // and is a string and does not start with a leading // `**`, we have to convert it to a relative pattern with // the given `base` if (typeof pattern === 'string' && !pattern.startsWith(GLOBSTAR) && !isAbsolute(pattern)) { return { base: path, pattern }; } return pattern; } </ins> export function parseWatcherPatterns(path: string, patterns: Array<string | IRelativePattern>): ParsedPattern[] { const parsedPatterns: ParsedPattern[] = []; for (const pattern of patterns) { <del> let normalizedPattern = pattern; // Patterns are always matched on the full absolute path // of the event. As such, if the pattern is not absolute // and does not start with a leading `**`, we have to // convert it to a relative pattern with the given `base` if (typeof normalizedPattern === 'string' && !normalizedPattern.startsWith(GLOBSTAR) && !isAbsolute(normalizedPattern)) { normalizedPattern = { base: path, pattern: normalizedPattern }; } parsedPatterns.push(parse(normalizedPattern)); </del> <ins> parsedPatterns.push(parse(normalizeWatcherPattern(path, pattern))); </ins> } return parsedPatterns;

// Logging if (requestsToStartWatching.length) { <del> this.trace(`Request to start watching: ${requestsToStartWatching.map(request => `${request.path} (excludes: ${request.excludes.length > 0 ? request.excludes : '<none>'}, includes: ${request.includes && request.includes.length > 0 ? request.includes : '<all>'})`).join(',')}`); </del> <ins> this.trace(`Request to start watching: ${requestsToStartWatching.map(request => `${request.path} (excludes: ${request.excludes.length > 0 ? request.excludes : '<none>'}, includes: ${request.includes && request.includes.length > 0 ? JSON.stringify(request.includes) : '<all>'})`).join(',')}`); </ins> } if (pathsToStopWatching.length) {

import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchFileService } from 'vs/workbench/services/files/common/files'; <ins> import { normalizeWatcherPattern } from 'vs/platform/files/common/watcher'; import { GLOBSTAR } from 'vs/base/common/glob'; import { rtrim } from 'vs/base/common/strings'; </ins> @extHostNamedCustomer(MainContext.MainThreadFileSystem) export class MainThreadFileSystem implements MainThreadFileSystemShape {

return this._fileService.activateProvider(scheme); } <del> $watch(extensionId: string, session: number, resource: UriComponents, opts: IWatchOptions): void { </del> <ins> async $watch(extensionId: string, session: number, resource: UriComponents, unvalidatedOpts: IWatchOptions): Promise<void> { </ins> const uri = URI.revive(resource); <del> const isInsideWorkspace = this._contextService.isInsideWorkspace(uri); </del> <ins> const workspaceFolder = this._contextService.getWorkspaceFolder(uri); const opts = { ...unvalidatedOpts }; // Convert a recursive watcher to a flat watcher if the path // turns out to not be a folder. Recursive watching is only // possible on folders, so we help all file watchers by checking // early. if (opts.recursive) { try { const stat = await this._fileService.stat(uri); if (!stat.isDirectory) { opts.recursive = false; } } catch (error) { this._logService.error(`MainThreadFileSystem#$watch(): failed to stat a resource for file watching (extension: ${extensionId}, path: ${uri.toString(true)}, recursive: ${opts.recursive}, session: ${session}): ${error}`); } } </ins> // Refuse to watch anything that is already watched via // our workspace watchers in case the request is a

// Still allow for non-recursive watch requests as a way // to bypass configured exlcude rules though // (see https://github.com/microsoft/vscode/issues/146066) <del> if (isInsideWorkspace && opts.recursive) { </del> <ins> if (workspaceFolder && opts.recursive) { </ins> this._logService.trace(`MainThreadFileSystem#$watch(): ignoring request to start watching because path is inside workspace (extension: ${extensionId}, path: ${uri.toString(true)}, recursive: ${opts.recursive}, session: ${session})`); return; }

// excluded via `files.watcherExclude`. As such, we configure // to include each configured exclude pattern so that only those // events are reported that are otherwise excluded. <del> else if (isInsideWorkspace) { </del> <ins> // However, we cannot just use the pattern as is, because a pattern // such as `bar` for a exclude, will work to exclude any of // `<workspace path>/bar` but will not work as include for files within // `bar` unless a suffix of `/**` if added. // (https://github.com/microsoft/vscode/issues/148245) else if (workspaceFolder) { </ins> const config = this._configurationService.getValue<IFilesConfiguration>(); if (config.files?.watcherExclude) { for (const key in config.files.watcherExclude) {

opts.includes = []; } <del> opts.includes.push(key); </del> <ins> const includePattern = `${rtrim(key, '/')}/${GLOBSTAR}`; opts.includes.push(normalizeWatcherPattern(workspaceFolder.uri.fsPath, includePattern)); </ins> } } }