Skip to content

Commit fe1ba4a

Browse files
authored
Update ty's JSON schema (SchemaStore#5175)
1 parent e14b338 commit fe1ba4a

File tree

1 file changed

+31
-1
lines changed

1 file changed

+31
-1
lines changed

src/schemas/json/ty.json

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,16 @@
368368
}
369369
]
370370
},
371+
"cyclic-type-alias-definition": {
372+
"title": "detects cyclic type alias definitions",
373+
"description": "## What it does\nChecks for type alias definitions that (directly or mutually) refer to themselves.\n\n## Why is it bad?\nAlthough it is permitted to define a recursive type alias, it is not meaningful\nto have a type alias whose expansion can only result in itself, and is therefore not allowed.\n\n## Examples\n```python\ntype Itself = Itself\n\ntype A = B\ntype B = A\n```",
374+
"default": "error",
375+
"oneOf": [
376+
{
377+
"$ref": "#/definitions/Level"
378+
}
379+
]
380+
},
371381
"deprecated": {
372382
"title": "detects uses of deprecated items",
373383
"description": "## What it does\nChecks for uses of deprecated items\n\n## Why is this bad?\nDeprecated items should no longer be used.\n\n## Examples\n```python\n@warnings.deprecated(\"use new_func instead\")\ndef old_func(): ...\n\nold_func() # emits [deprecated] diagnostic\n```",
@@ -620,7 +630,7 @@
620630
},
621631
"invalid-method-override": {
622632
"title": "detects method definitions that violate the Liskov Substitution Principle",
623-
"description": "## What it does\nDetects method overrides that violate the [Liskov Substitution Principle] (\"LSP\").\n\nThe LSP states that an instance of a subtype should be substitutable for an instance of its supertype.\nApplied to Python, this means:\n1. All argument combinations a superclass method accepts\n must also be accepted by an overriding subclass method.\n2. The return type of an overriding subclass method must be a subtype\n of the return type of the superclass method.\n\n## Why is this bad?\nViolating the Liskov Substitution Principle will lead to many of ty's assumptions and\ninferences being incorrect, which will mean that it will fail to catch many possible\ntype errors in your code.\n\n## Example\n```python\nclass Super:\n def method(self, x) -> int:\n return 42\n\nclass Sub(Super):\n # Liskov violation: `str` is not a subtype of `int`,\n # but the supertype method promises to return an `int`.\n def method(self, x) -> str: # error: [invalid-override]\n return \"foo\"\n\ndef accepts_super(s: Super) -> int:\n return s.method(x=42)\n\naccepts_super(Sub()) # The result of this call is a string, but ty will infer\n # it to be an `int` due to the violation of the Liskov Substitution Principle.\n\nclass Sub2(Super):\n # Liskov violation: the superclass method can be called with a `x=`\n # keyword argument, but the subclass method does not accept it.\n def method(self, y) -> int: # error: [invalid-override]\n return 42\n\naccepts_super(Sub2()) # TypeError at runtime: method() got an unexpected keyword argument 'x'\n # ty cannot catch this error due to the violation of the Liskov Substitution Principle.\n```\n\n## Common issues\n\n### Why does ty complain about my `__eq__` method?\n\n`__eq__` and `__ne__` methods in Python are generally expected to accept arbitrary\nobjects as their second argument, for example:\n\n```python\nclass A:\n x: int\n\n def __eq__(self, other: object) -> bool:\n # gracefully handle an object of an unexpected type\n # without raising an exception\n if not isinstance(other, A):\n return False\n return self.x == other.x\n```\n\nIf `A.__eq__` here were annotated as only accepting `A` instances for its second argument,\nit would imply that you wouldn't be able to use `==` between instances of `A` and\ninstances of unrelated classes without an exception possibly being raised. While some\nclasses in Python do indeed behave this way, the strongly held convention is that it should\nbe avoided wherever possible. As part of this check, therefore, ty enforces that `__eq__`\nand `__ne__` methods accept `object` as their second argument.\n\n[Liskov Substitution Principle]: https://en.wikipedia.org/wiki/Liskov_substitution_principle",
633+
"description": "## What it does\nDetects method overrides that violate the [Liskov Substitution Principle] (\"LSP\").\n\nThe LSP states that an instance of a subtype should be substitutable for an instance of its supertype.\nApplied to Python, this means:\n1. All argument combinations a superclass method accepts\n must also be accepted by an overriding subclass method.\n2. The return type of an overriding subclass method must be a subtype\n of the return type of the superclass method.\n\n## Why is this bad?\nViolating the Liskov Substitution Principle will lead to many of ty's assumptions and\ninferences being incorrect, which will mean that it will fail to catch many possible\ntype errors in your code.\n\n## Example\n```python\nclass Super:\n def method(self, x) -> int:\n return 42\n\nclass Sub(Super):\n # Liskov violation: `str` is not a subtype of `int`,\n # but the supertype method promises to return an `int`.\n def method(self, x) -> str: # error: [invalid-override]\n return \"foo\"\n\ndef accepts_super(s: Super) -> int:\n return s.method(x=42)\n\naccepts_super(Sub()) # The result of this call is a string, but ty will infer\n # it to be an `int` due to the violation of the Liskov Substitution Principle.\n\nclass Sub2(Super):\n # Liskov violation: the superclass method can be called with a `x=`\n # keyword argument, but the subclass method does not accept it.\n def method(self, y) -> int: # error: [invalid-override]\n return 42\n\naccepts_super(Sub2()) # TypeError at runtime: method() got an unexpected keyword argument 'x'\n # ty cannot catch this error due to the violation of the Liskov Substitution Principle.\n```\n\n## Common issues\n\n### Why does ty complain about my `__eq__` method?\n\n`__eq__` and `__ne__` methods in Python are generally expected to accept arbitrary\nobjects as their second argument, for example:\n\n```python\nclass A:\n x: int\n\n def __eq__(self, other: object) -> bool:\n # gracefully handle an object of an unexpected type\n # without raising an exception\n if not isinstance(other, A):\n return False\n return self.x == other.x\n```\n\nIf `A.__eq__` here were annotated as only accepting `A` instances for its second argument,\nit would imply that you wouldn't be able to use `==` between instances of `A` and\ninstances of unrelated classes without an exception possibly being raised. While some\nclasses in Python do indeed behave this way, the strongly held convention is that it should\nbe avoided wherever possible. As part of this check, therefore, ty enforces that `__eq__`\nand `__ne__` methods accept `object` as their second argument.\n\n### Why does ty disagree with Ruff about how to write my method?\n\nRuff has several rules that will encourage you to rename a parameter, or change its type\nsignature, if it thinks you're falling into a certain anti-pattern. For example, Ruff's\n[ARG002](https://docs.astral.sh/ruff/rules/unused-method-argument/) rule recommends that an\nunused parameter should either be removed or renamed to start with `_`. Applying either of\nthese suggestions can cause ty to start reporting an `invalid-method-override` error if\nthe function in question is a method on a subclass that overrides a method on a superclass,\nand the change would cause the subclass method to no longer accept all argument combinations\nthat the superclass method accepts.\n\nThis can usually be resolved by adding [`@typing.override`][override] to your method\ndefinition. Ruff knows that a method decorated with `@typing.override` is intended to\noverride a method by the same name on a superclass, and avoids reporting rules like ARG002\nfor such methods; it knows that the changes recommended by ARG002 would violate the Liskov\nSubstitution Principle.\n\nCorrect use of `@override` is enforced by ty's `invalid-explicit-override` rule.\n\n[Liskov Substitution Principle]: https://en.wikipedia.org/wiki/Liskov_substitution_principle\n[override]: https://docs.python.org/3/library/typing.html#typing.override",
624634
"default": "error",
625635
"oneOf": [
626636
{
@@ -738,6 +748,16 @@
738748
}
739749
]
740750
},
751+
"invalid-type-arguments": {
752+
"title": "detects invalid type arguments in generic specialization",
753+
"description": "## What it does\nChecks for invalid type arguments in explicit type specialization.\n\n## Why is this bad?\nProviding the wrong number of type arguments or type arguments that don't\nsatisfy the type variable's bounds or constraints will lead to incorrect\ntype inference and may indicate a misunderstanding of the generic type's\ninterface.\n\n## Examples\n\nUsing legacy type variables:\n```python\nfrom typing import Generic, TypeVar\n\nT1 = TypeVar('T1', int, str)\nT2 = TypeVar('T2', bound=int)\n\nclass Foo1(Generic[T1]): ...\nclass Foo2(Generic[T2]): ...\n\nFoo1[bytes] # error: bytes does not satisfy T1's constraints\nFoo2[str] # error: str does not satisfy T2's bound\n```\n\nUsing PEP 695 type variables:\n```python\nclass Foo[T]: ...\nclass Bar[T, U]: ...\n\nFoo[int, str] # error: too many arguments\nBar[int] # error: too few arguments\n```",
754+
"default": "error",
755+
"oneOf": [
756+
{
757+
"$ref": "#/definitions/Level"
758+
}
759+
]
760+
},
741761
"invalid-type-checking-constant": {
742762
"title": "detects invalid `TYPE_CHECKING` constant assignments",
743763
"description": "## What it does\nChecks for a value other than `False` assigned to the `TYPE_CHECKING` variable, or an\nannotation not assignable from `bool`.\n\n## Why is this bad?\nThe name `TYPE_CHECKING` is reserved for a flag that can be used to provide conditional\ncode seen only by the type checker, and not at runtime. Normally this flag is imported from\n`typing` or `typing_extensions`, but it can also be defined locally. If defined locally, it\nmust be assigned the value `False` at runtime; the type checker will consider its value to\nbe `True`. If annotated, it must be annotated as a type that can accept `bool` values.\n\n## Examples\n```python\nTYPE_CHECKING: str\nTYPE_CHECKING = ''\n```",
@@ -838,6 +858,16 @@
838858
}
839859
]
840860
},
861+
"override-of-final-method": {
862+
"title": "detects overrides of final methods",
863+
"description": "## What it does\nChecks for methods on subclasses that override superclass methods decorated with `@final`.\n\n## Why is this bad?\nDecorating a method with `@final` declares to the type checker that it should not be\noverridden on any subclass.\n\n## Example\n\n```python\nfrom typing import final\n\nclass A:\n @final\n def foo(self): ...\n\nclass B(A):\n def foo(self): ... # Error raised here\n```",
864+
"default": "error",
865+
"oneOf": [
866+
{
867+
"$ref": "#/definitions/Level"
868+
}
869+
]
870+
},
841871
"parameter-already-assigned": {
842872
"title": "detects multiple arguments for the same parameter",
843873
"description": "## What it does\nChecks for calls which provide more than one argument for a single parameter.\n\n## Why is this bad?\nProviding multiple values for a single parameter will raise a `TypeError` at runtime.\n\n## Examples\n\n```python\ndef f(x: int) -> int: ...\n\nf(1, x=2) # Error raised here\n```",

0 commit comments

Comments
 (0)