Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove incorrect diagnostic for invalid python identifier in dataclass field aliases and prevent them from appearing in completions #838

Merged
merged 4 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"editor.unicodeHighlight.nonBasicASCII": true,
"ruff.nativeServer": true,
"typescript.inlayHints.parameterNames.enabled": "literals",
"jest.jestCommandLine": "npm run jest --",
"files.readonlyInclude": {
".pdm-build/**/*": true,
".pdm-python": true,
Expand Down
9 changes: 0 additions & 9 deletions packages/pyright-internal/src/analyzer/dataClasses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
ParseNodeType,
TypeAnnotationNode,
} from '../parser/parseNodes';
import { Tokenizer } from '../parser/tokenizer';
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
import { getFileInfo } from './analyzerNodeInfo';
import { ConstraintSolution } from './constraintSolution';
Expand Down Expand Up @@ -333,14 +332,6 @@ export function synthesizeDataClassMethods(
isLiteralType(valueType)
) {
aliasName = valueType.priv.literalValue as string;

if (!Tokenizer.isPythonIdentifier(aliasName)) {
evaluator.addDiagnostic(
DiagnosticRule.reportGeneralTypeIssues,
LocMessage.dataClassFieldInvalidAlias().format({ aliasName }),
aliasArg.d.valueExpr
);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ import {
} from './completionProviderUtils';
import { DocumentSymbolCollector } from './documentSymbolCollector';
import { getAutoImportText, getDocumentationPartsForTypeAndDecl } from './tooltipUtils';
import { Tokenizer } from '../parser/tokenizer';

namespace Keywords {
const base: string[] = [
Expand Down Expand Up @@ -2891,6 +2892,8 @@ export class CompletionProvider {
paramDetails.params.forEach((paramInfo) => {
if (
paramInfo.param.name &&
// filter out any dataclass field aliases that aren't valid identifiers
Tokenizer.isPythonIdentifier(paramInfo.param.name) &&
paramInfo.kind !== ParamKind.Positional &&
paramInfo.kind !== ParamKind.ExpandedArgs
) {
Expand Down
2 changes: 0 additions & 2 deletions packages/pyright-internal/src/localization/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,6 @@ export namespace Localizer {
);
export const dataClassFieldInheritedDefault = () =>
new ParameterizedString<{ fieldName: string }>(getRawString('Diagnostic.dataClassFieldInheritedDefault'));
export const dataClassFieldInvalidAlias = () =>
new ParameterizedString<{ aliasName: string }>(getRawString('Diagnostic.dataClassFieldInvalidAlias'));
export const dataClassFieldWithDefault = () => getRawString('Diagnostic.dataClassFieldWithDefault');
export const dataClassFieldWithoutAnnotation = () => getRawString('Diagnostic.dataClassFieldWithoutAnnotation');
export const dataClassFieldWithPrivateName = () => getRawString('Diagnostic.dataClassFieldWithPrivateName');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "Argument typu {argType} není platný převaděč pro pole {fieldName} typu {fieldType}",
"dataClassConverterOverloads": "Žádná přetížení {funcName} nejsou platné převaděče pro pole {fieldName} typu {fieldType}",
"dataClassFieldInheritedDefault": "{fieldName} přepíše pole se stejným názvem, ale chybí mu výchozí hodnota.",
"dataClassFieldInvalidAlias": "Název aliasu {aliasName} není platný identifikátor.",
"dataClassFieldWithDefault": "Pole bez výchozích hodnot se nemůžou zobrazit po polích s výchozími hodnotami",
"dataClassFieldWithPrivateName": "Pole datové třídy nemůže používat privátní název",
"dataClassFieldWithoutAnnotation": "Pole dataclass bez poznámky typu způsobí výjimku modulu runtime",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "Das Argument vom Typ \"{argType}\" ist kein gültiger Konverter für das Feld \"{fieldName}\" vom Typ \"{fieldType}\"",
"dataClassConverterOverloads": "Keine Überladungen von \"{funcName}\" sind gültige Konverter für das Feld \"{fieldName}\" vom Typ \"{fieldType}\"",
"dataClassFieldInheritedDefault": "„{fieldName}“ überschreibt ein Feld mit demselben Namen, aber es fehlt ein Standardwert",
"dataClassFieldInvalidAlias": "Der Aliasname „{aliasName}“ ist kein gültiger Bezeichner.",
"dataClassFieldWithDefault": "Felder ohne Standardwerte dürfen nicht nach Feldern mit Standardwerten angezeigt werden.",
"dataClassFieldWithPrivateName": "Das Feld \"Dataclass\" kann keinen privaten Namen verwenden.",
"dataClassFieldWithoutAnnotation": "Datenklassenfeld ohne Typanmerkung verursacht eine Laufzeitausnahme",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@
"dataClassConverterFunction": "Argument of type \"{argType}\" is not a valid converter for field \"{fieldName}\" of type \"{fieldType}\"",
"dataClassConverterOverloads": "No overloads of \"{funcName}\" are valid converters for field \"{fieldName}\" of type \"{fieldType}\"",
"dataClassFieldInheritedDefault": "\"{fieldName}\" overrides a field of the same name but is missing a default value",
"dataClassFieldInvalidAlias": "Alias name \"{aliasName}\" is not a valid identifier",
"dataClassFieldWithDefault": "Fields without default values cannot appear after fields with default values",
"dataClassFieldWithPrivateName": "Dataclass field cannot use private name",
"dataClassFieldWithoutAnnotation": "Dataclass field without type annotation will cause runtime exception",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "Argumento de tipo \"{argType}\" no es un convertidor válido para el campo \"{fieldName}\" de tipo \"{fieldType}\"",
"dataClassConverterOverloads": "No hay sobrecargas de \"{funcName}\" que sean convertidores válidos para el campo \"{fieldName}\" de tipo \"{fieldType}\"",
"dataClassFieldInheritedDefault": "\"{fieldName}\" invalida un campo con el mismo nombre, pero falta un valor predeterminado",
"dataClassFieldInvalidAlias": "El nombre de alias \"{aliasName}\" no es un identificador válido",
"dataClassFieldWithDefault": "Los campos sin valores predeterminados no pueden aparecer después de los campos con valores predeterminados",
"dataClassFieldWithPrivateName": "El campo Dataclass no puede utilizar un nombre privado",
"dataClassFieldWithoutAnnotation": "El campo Dataclass sin anotación de tipo provocará una excepción en tiempo de ejecución",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "L’argument de type « {argType} » n’est pas un convertisseur valide pour le champ « {fieldName} » de type « {fieldType} »",
"dataClassConverterOverloads": "Aucune surcharge de « {funcName} » n’est valide pour le champ « {fieldName} » de type « {fieldType} »",
"dataClassFieldInheritedDefault": "« {fieldName} » remplace un champ du même nom mais n’a pas de valeur par défaut",
"dataClassFieldInvalidAlias": "Le nom d’alias « {aliasName} » n’est pas un identificateur valide",
"dataClassFieldWithDefault": "Les champs sans valeurs par défaut ne peuvent pas apparaître après les champs avec des valeurs par défaut",
"dataClassFieldWithPrivateName": "Le champ Dataclass ne peut pas utiliser de nom privé",
"dataClassFieldWithoutAnnotation": "Le champ Dataclass sans annotation de type provoquera une exception d'exécution",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "L'argomento di tipo \"{argType}\" non è un convertitore valido per il campo \"{fieldName}\" di tipo \"{fieldType}\"",
"dataClassConverterOverloads": "Nessun overload di \"{funcName}\" è un convertitore valido per il campo \"{fieldName}\" di tipo \"{fieldType}\"",
"dataClassFieldInheritedDefault": "\"{fieldName}\" esegue l'override di un campo con lo stesso nome, ma manca un valore predefinito",
"dataClassFieldInvalidAlias": "Il nome alias \"{aliasName}\" non è un identificatore valido",
"dataClassFieldWithDefault": "I campi senza valori predefiniti non possono essere visualizzati dopo i campi con valori predefiniti",
"dataClassFieldWithPrivateName": "Il campo dataclass non può usare un nome privato",
"dataClassFieldWithoutAnnotation": "Il campo dataclass senza annotazione del tipo causerà un'eccezione di runtime",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "型 \"{argType}\" の引数は、型 \"{fieldType}\" のフィールド \"{fieldName}\" の有効なコンバーターではありません",
"dataClassConverterOverloads": "{funcName}\" のオーバーロードは、型 \"{fieldType}\" のフィールド \"{fieldName}\" に対して有効なコンバーターではありません",
"dataClassFieldInheritedDefault": "\"{fieldName}\" は同じ名前のフィールドをオーバーライドしますが、既定値がありません",
"dataClassFieldInvalidAlias": "エイリアス名 \"{aliasName}\" は有効な識別子ではありません",
"dataClassFieldWithDefault": "既定値のないフィールドは、既定値を持つフィールドの後に表示できません",
"dataClassFieldWithPrivateName": "データクラス フィールドはプライベート名を使用できません",
"dataClassFieldWithoutAnnotation": "型注釈のないデータクラス フィールドが原因でランタイム例外が発生する",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "\"{argType}\" 형식의 인수는 \"{fieldType}\" 형식의 \"{fieldName}\" 필드에 유효한 변환기가 아닙니다.",
"dataClassConverterOverloads": "\"{funcName}\"의 오버로드는 \"{fieldType}\" 형식의 \"{fieldName}\" 필드에 유효한 변환기가 아닙니다.",
"dataClassFieldInheritedDefault": "\"{fieldName}\"이(가) 같은 이름의 필드를 재정의하지만 기본값이 없음",
"dataClassFieldInvalidAlias": "별칭 이름 \"{aliasName}\"은(는) 유효한 식별자가 아닙니다.",
"dataClassFieldWithDefault": "기본값이 없는 필드는 기본값이 있는 필드 뒤에 나타날 수 없습니다.",
"dataClassFieldWithPrivateName": "데이터 클래스 필드는 프라이빗 이름을 사용할 수 없습니다.",
"dataClassFieldWithoutAnnotation": "형식 주석이 없는 데이터 클래스 필드를 사용하면 런타임 예외가 발생합니다.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "Argument typu „{argType}” nie jest prawidłowym konwerterem pola „{fieldName}” typu „{fieldType}”",
"dataClassConverterOverloads": "Żadne przeciążenia „{funcName}” nie są prawidłowymi konwerterami dla pola „{fieldName}” typu „{fieldType}”",
"dataClassFieldInheritedDefault": "Pole „{fieldName}” zastępuje pole o tej samej nazwie, ale brakuje wartości domyślnej",
"dataClassFieldInvalidAlias": "Nazwa aliasu „{aliasName}” nie jest prawidłowym identyfikatorem",
"dataClassFieldWithDefault": "Pola bez wartości domyślnych nie mogą występować po polach z wartościami domyślnymi",
"dataClassFieldWithPrivateName": "Pole klasy danych nie może używać nazwy prywatnej",
"dataClassFieldWithoutAnnotation": "Pole klasy danych bez adnotacji typu spowoduje wyjątek środowiska uruchomieniowego",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "O argumento do tipo \"{argType}\" não é um conversor válido para o campo \"{fieldName}\" do tipo \"{fieldType}\"",
"dataClassConverterOverloads": "Nenhuma sobrecarga de \"{funcName}\" são conversores válidos para o campo \"{fieldName}\" do tipo \"{fieldType}\"",
"dataClassFieldInheritedDefault": "\"{fieldName}\" substitui um campo com o mesmo nome, mas não possui um valor padrão",
"dataClassFieldInvalidAlias": "O nome de alias \"{aliasName}\" não é um identificador válido",
"dataClassFieldWithDefault": "Campos sem valores padrão não podem aparecer após campos com valores padrão",
"dataClassFieldWithPrivateName": "O campo Dataclass não pode usar o nome privado",
"dataClassFieldWithoutAnnotation": "O campo Dataclass sem anotação de tipo causará uma exceção de runtime",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "[FxD8r][นั้Ærgµmëñt øf tÿpë \"{ærgTÿpë}\" ïs ñøt æ vælïð çøñvërtër før fïëlð \"{fïëlðÑæmë}\" øf tÿpë \"{fïëlðTÿpë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृนั้ढूँ]",
"dataClassConverterOverloads": "[ZJ0SE][นั้Ñø øvërløæðs øf \"{fµñçÑæmë}\" ærë vælïð çøñvërtërs før fïëlð \"{fïëlðÑæmë}\" øf tÿpë \"{fïëlðTÿpë}\"Ấğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्นั้ढूँ]",
"dataClassFieldInheritedDefault": "[BKxvn][นั้\"{fïëlðÑæmë}\" øvërrïðës æ fïëlð øf thë sæmë ñæmë þµt ïs mïssïñg æ ðëfæµlt vælµëẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğ倪İนั้ढूँ]",
"dataClassFieldInvalidAlias": "[Yie5U][นั้Ælïæs ñæmë \"{ælïæsÑæmë}\" ïs ñøt æ vælïð ïðëñtïfïërẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰนั้ढूँ]",
"dataClassFieldWithDefault": "[iJuju][นั้Fïëlðs wïthøµt ðëfæµlt vælµës çæññøt æppëær æftër fïëlðs wïth ðëfæµlt vælµësẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृまẤğนั้ढूँ]",
"dataClassFieldWithPrivateName": "[miQYb][นั้Ðætæçlæss fïëlð çæññøt µsë prïvætë ñæmëẤğ倪İЂҰक्र्तिृまẤğนั้ढूँ]",
"dataClassFieldWithoutAnnotation": "[zq5t5][นั้Ðætæçlæss fïëlð wïthøµt tÿpë æññøtætïøñ wïll çæµsë rµñtïmë ëxçëptïøñẤğ倪İЂҰक्र्तिृまẤğ倪İЂҰक्र्तिृนั้ढूँ]",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "Аргумент типа \"{argType}\" не является допустимым преобразователем для поля \"{fieldName}\" типа \"{fieldType}\"",
"dataClassConverterOverloads": "Ни одна перегрузка \"{funcName}\" не является допустимым преобразователем поля \"{fieldName}\" типа \"{fieldType}\"",
"dataClassFieldInheritedDefault": "\"{fieldName}\" переопределяет поле с тем же именем, но в нем отсутствует значение по умолчанию",
"dataClassFieldInvalidAlias": "Псевдоним \"{aliasName}\" не является допустимым идентификатором",
"dataClassFieldWithDefault": "Поля со значениями по умолчанию должны идти после полей без значений по умолчанию",
"dataClassFieldWithPrivateName": "Поле датакласса не может использовать приватное имя",
"dataClassFieldWithoutAnnotation": "Поле датакласса без аннотации типа вызовет исключение",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "\"{argType}\" türündeki bağımsız değişken, \"{fieldName}\" türündeki \"{fieldType}\" alanı için geçerli bir dönüştürücü değil",
"dataClassConverterOverloads": "\"{funcName}\" işlevinin aşırı yüklemelerinden hiçbiri \"{fieldType}\" türündeki \"{fieldName}\" alanı için geçerli dönüştürücüler değil",
"dataClassFieldInheritedDefault": "\"{fieldName}\", aynı ada sahip bir alanı geçersiz kılıyor ancak varsayılan değeri yok",
"dataClassFieldInvalidAlias": "\"{aliasName}\" diğer adı geçerli bir tanımlayıcı değil",
"dataClassFieldWithDefault": "Varsayılan değerleri olmayan alanlar, varsayılan değerleri olan alanlardan sonra gelemez",
"dataClassFieldWithPrivateName": "Veri sınıfı alanı özel ad kullanamıyor",
"dataClassFieldWithoutAnnotation": "Tür ek açıklaması olmayan veri sınıfı alanı çalışma zamanı özel durumuna neden olur",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
"dataClassConverterFunction": "\"{argType}\" 类型的参数不是 \"{fieldType}\" 类型的字段 \"{fieldName}\" 的合法转换器",
"dataClassConverterOverloads": "\"{funcName}\" 的重载不是 \"{fieldType}\" 类型的字段 \"{fieldName}\" 的合法转换器",
"dataClassFieldInheritedDefault": "\"{fieldName}\" 覆盖了(父类的)同名字段,但未给定默认值",
"dataClassFieldInvalidAlias": "别名标识符 \"{aliasName}\" 无效",
"dataClassFieldWithDefault": "没有默认值的字段不能出现在具有默认值的字段之后",
"dataClassFieldWithPrivateName": "`dataclass` 的字段不能使用私有名称",
"dataClassFieldWithoutAnnotation": "缺少类型注解的 `dataclass` 字段将导致运行时异常",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@
"dataClassConverterFunction": "類型 \"{argType}\" 的引數不是類型 \"{fieldType}\" 欄位 \"{fieldName}\" 的有效轉換程式",
"dataClassConverterOverloads": "\"{funcName}\" 沒有任何多載是類型 \"{fieldType}\" 欄位 \"{fieldName}\" 的有效轉換程式",
"dataClassFieldInheritedDefault": "\"{fieldName}\" 覆寫相同名稱的欄位,但缺少預設值",
"dataClassFieldInvalidAlias": "別名名稱 \"{aliasName}\" 並非有效的識別碼",
"dataClassFieldWithDefault": "沒有預設值的欄位無法出現在具有預設值的欄位後面",
"dataClassFieldWithPrivateName": "Dataclass 欄位不能使用私人名稱",
"dataClassFieldWithoutAnnotation": "沒有型別註釋的 Dataclass 欄位會造成執行階段例外狀況",
Expand Down
44 changes: 44 additions & 0 deletions packages/pyright-internal/src/tests/completions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1410,3 +1410,47 @@ test('enum with regular base type', async () => {
},
});
});

test('dataclass field alias with invalid python identifier', async () => {
const code = `
// @filename: test.py
//// from typing import dataclass_transform
////
////
//// def field[T](*, init: bool = True, default: T | None = None, alias: str | None = None) -> T: ...
////
//// @dataclass_transform(field_specifiers=(field,))
//// class Foo(type):...
////
//// class Bar(metaclass=Foo):...
////
//// class Baz(Bar):
//// a: int = field(alias='foo bar')
//// b: str = field(alias='baz')
////
//// Baz([|/*marker*/|])
`;

const state = parseAndGetTestState(code).state;

await state.verifyCompletion('included', 'markdown', {
['marker']: {
completions: [
{
label: 'baz=',
kind: CompletionItemKind.Variable,
},
],
},
});
await state.verifyCompletion('excluded', 'markdown', {
['marker']: {
completions: [
{
label: 'foo bar=',
kind: CompletionItemKind.Variable,
},
],
},
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,6 @@ class Customer3(ModelBaseFrozen):


class Customer4(ModelBase):
# This should generate an error because alias must be a valid identifier.
name1: str = model_field(alias="other name")

# This should generate an error because alias must be a valid identifier.
name2: str = model_field(alias="+test")
2 changes: 1 addition & 1 deletion packages/pyright-internal/src/tests/typeEvaluator5.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ test('DataclassTransform2', () => {
test('DataclassTransform3', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['dataclassTransform3.py']);

TestUtils.validateResults(analysisResults, 8);
TestUtils.validateResults(analysisResults, 6);
});

test('DataclassTransform4', () => {
Expand Down
Loading