From 367863ec0489e1f53312339f72557b1fe6bdc507 Mon Sep 17 00:00:00 2001 From: alliasgher Date: Tue, 14 Apr 2026 11:07:02 +0500 Subject: [PATCH 1/2] tokenizer: accept ':' in type: ignore code names for namespaced codes The regular expression for type: ignore and pyright: ignore comments used the character class [\s\w-,] for the codes inside [...]. This excluded ':' so tool-namespaced codes such as "ty:unresolved-reference" (introduced in ty/ruff) failed to match, causing the comment to be ignored and the diagnostic to fire. Extend the class to [\s\w:,-] so that namespaced codes are accepted. Fixes #11345 Signed-off-by: alliasgher --- .../pyright-internal/src/parser/tokenizer.ts | 6 ++++- .../src/tests/tokenizer.test.ts | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/pyright-internal/src/parser/tokenizer.ts b/packages/pyright-internal/src/parser/tokenizer.ts index 562328586787..416532935708 100644 --- a/packages/pyright-internal/src/parser/tokenizer.ts +++ b/packages/pyright-internal/src/parser/tokenizer.ts @@ -142,7 +142,11 @@ const _byteOrderMarker = 0xfeff; const defaultTabSize = 8; const magicsRegEx = /\\\s*$/; -const typeIgnoreCommentRegEx = /((^|#)\s*)type:\s*ignore(\s*\[([\s\w-,]*)\]|\s|$)/; +// The character class for type: ignore rule codes includes ':' so that +// tool-namespaced codes such as "ty:unresolved-reference" are accepted. +// pyright: ignore uses the original class since tool-namespaced codes +// are not expected there. +const typeIgnoreCommentRegEx = /((^|#)\s*)type:\s*ignore(\s*\[([\s\w:,-]*)\]|\s|$)/; const pyrightIgnoreCommentRegEx = /((^|#)\s*)pyright:\s*ignore(\s*\[([\s\w-,]*)\]|\s|$)/; const underscoreRegEx = /_/g; diff --git a/packages/pyright-internal/src/tests/tokenizer.test.ts b/packages/pyright-internal/src/tests/tokenizer.test.ts index d755a972498f..d4d940b45a0f 100644 --- a/packages/pyright-internal/src/tests/tokenizer.test.ts +++ b/packages/pyright-internal/src/tests/tokenizer.test.ts @@ -1815,6 +1815,33 @@ test('TypeIgnoreLine2', () => { assert.equal(results.tokens.contains(42), false); }); +// Regression test for https://github.com/microsoft/pyright/issues/11345. +// type: ignore comments containing tool-namespaced codes (e.g. "ty:rule-name") +// must be recognised as type: ignore comments. +test('TypeIgnoreNamespacedCode', () => { + const t = new Tokenizer(); + // Single namespaced code. + let results = t.tokenize('a = 1 # type: ignore[ty:unresolved-reference]'); + assert.equal(results.typeIgnoreLines.size, 1); + assert(results.typeIgnoreLines.has(0)); + const rules = results.typeIgnoreLines.get(0)!.rulesList; + assert(rules !== undefined); + assert.equal(rules.length, 1); + assert.equal(rules[0].text, 'ty:unresolved-reference'); +}); + +test('TypeIgnoreMixedNamespacedCodes', () => { + const t = new Tokenizer(); + // Mix of plain and namespaced codes. + let results = t.tokenize('a = 1 # type: ignore[name-defined, ty:unresolved-reference]'); + assert.equal(results.typeIgnoreLines.size, 1); + const rules = results.typeIgnoreLines.get(0)!.rulesList; + assert(rules !== undefined); + assert.equal(rules.length, 2); + assert.equal(rules[0].text, 'name-defined'); + assert.equal(rules[1].text, 'ty:unresolved-reference'); +}); + test('Constructor', () => { const t = new Tokenizer(); const results = t.tokenize('def constructor'); From 7988b5c508f9088a09cf4e3d787e01c1040dd074 Mon Sep 17 00:00:00 2001 From: alliasgher Date: Tue, 14 Apr 2026 21:55:17 +0500 Subject: [PATCH 2/2] tests: use const instead of let in tokenizer tests Signed-off-by: alliasgher --- packages/pyright-internal/src/tests/tokenizer.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pyright-internal/src/tests/tokenizer.test.ts b/packages/pyright-internal/src/tests/tokenizer.test.ts index d4d940b45a0f..32f92009bbd1 100644 --- a/packages/pyright-internal/src/tests/tokenizer.test.ts +++ b/packages/pyright-internal/src/tests/tokenizer.test.ts @@ -1821,7 +1821,7 @@ test('TypeIgnoreLine2', () => { test('TypeIgnoreNamespacedCode', () => { const t = new Tokenizer(); // Single namespaced code. - let results = t.tokenize('a = 1 # type: ignore[ty:unresolved-reference]'); + const results = t.tokenize('a = 1 # type: ignore[ty:unresolved-reference]'); assert.equal(results.typeIgnoreLines.size, 1); assert(results.typeIgnoreLines.has(0)); const rules = results.typeIgnoreLines.get(0)!.rulesList; @@ -1833,7 +1833,7 @@ test('TypeIgnoreNamespacedCode', () => { test('TypeIgnoreMixedNamespacedCodes', () => { const t = new Tokenizer(); // Mix of plain and namespaced codes. - let results = t.tokenize('a = 1 # type: ignore[name-defined, ty:unresolved-reference]'); + const results = t.tokenize('a = 1 # type: ignore[name-defined, ty:unresolved-reference]'); assert.equal(results.typeIgnoreLines.size, 1); const rules = results.typeIgnoreLines.get(0)!.rulesList; assert(rules !== undefined);