Skip to content

Commit 535c1f2

Browse files
authored
Add some challenges (#11)
1 parent 42a9818 commit 535c1f2

File tree

6 files changed

+240
-0
lines changed

6 files changed

+240
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
TODO:
3+
4+
Create a descriptor and adorn the __get__ method with the @typing.overload decorator to ensure the functionality of the test case.
5+
6+
NOTE: Craft at least two overload declarations:
7+
8+
- one to handle the case when the instance is None (i.e., accessing TestClass.a), and another...
9+
- ...to cater to any instance of TestClass.
10+
11+
NOTE: By explicitly binding the instance parameter to the TestClass class, the test cases can also be successfully passed.
12+
"""
13+
14+
15+
class Descriptor:
16+
def __get__(self, instance: ..., owner: ...):
17+
"""you don't need to implement this"""
18+
...
19+
20+
21+
## End of your code ##
22+
class TestClass:
23+
a = Descriptor()
24+
25+
26+
def descriptor_self(x: Descriptor) -> None:
27+
...
28+
29+
30+
def string_value(x: str) -> None:
31+
...
32+
33+
34+
descriptor_self(TestClass.a)
35+
string_value(TestClass().a)
36+
37+
descriptor_self(TestClass().a) # expect-type-error
38+
string_value(TestClass.a) # expect-type-error
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
TODO:
3+
4+
Define a descriptor, make test case works.
5+
"""
6+
7+
from typing import overload, Self, Any
8+
9+
10+
class Descriptor:
11+
@overload
12+
def __get__(self, instance: None, owner: type) -> Self:
13+
...
14+
15+
@overload
16+
def __get__(self, instance: Any, owner: type) -> str:
17+
...
18+
19+
def __get__(self, instance: Any, owner: type) -> Self | str:
20+
if instance is None:
21+
return self
22+
23+
return ""
24+
25+
26+
## End of your code ##
27+
class TestClass:
28+
a = Descriptor()
29+
30+
31+
def descriptor_self(x: Descriptor) -> None:
32+
...
33+
34+
35+
def string_value(x: str) -> None:
36+
...
37+
38+
39+
descriptor_self(TestClass.a)
40+
string_value(TestClass().a)
41+
42+
descriptor_self(TestClass().a) # expect-type-error
43+
string_value(TestClass.a) # expect-type-error
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
TODO:
3+
4+
a method-like descriptor, implements the `__get__` only.
5+
"""
6+
from typing import ParamSpec, TypeVar, Concatenate, Callable, Generic
7+
8+
P = ParamSpec("P")
9+
T = TypeVar("T")
10+
R = TypeVar("R")
11+
12+
13+
class MyMethod(Generic[T, P, R]):
14+
def __init__(self, func: Callable[Concatenate[T, P], R]) -> None:
15+
self.func = func
16+
17+
def __get__(self, instance, owner) -> None:
18+
return
19+
20+
21+
## End of your code ##
22+
class Foo:
23+
@MyMethod
24+
def do_something(self, value: int) -> None:
25+
...
26+
27+
28+
foo = Foo()
29+
30+
Foo.do_something(foo, 1111)
31+
foo.do_something(1111)
32+
33+
34+
Foo.do_something(1111) # expect-type-error
35+
foo.do_something(11111, foo) # expect-type-error
36+
foo.do_something(foo, 11111) # expect-type-error
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"""
2+
TODO:
3+
4+
a method-like descriptor, implements the `__get__` only.
5+
"""
6+
from typing import Any, ParamSpec, TypeVar, Concatenate, Callable, Generic, overload
7+
8+
P = ParamSpec("P")
9+
T = TypeVar("T")
10+
R = TypeVar("R")
11+
12+
13+
class MyMethod(Generic[T, P, R]):
14+
def __init__(self, func: Callable[Concatenate[T, P], R]) -> None:
15+
self.func = func
16+
17+
@overload
18+
def __get__(self, instance: None, owner: type) -> Callable[Concatenate[T, P], R]:
19+
...
20+
21+
@overload
22+
def __get__(self, instance: Any, owner: type) -> Callable[P, R]:
23+
...
24+
25+
def __get__(self, instance: Any | None, owner: type):
26+
if instance is None:
27+
return self.func
28+
29+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
30+
return self.func(instance, *args, **kwargs)
31+
32+
return wrapper
33+
34+
35+
## End of your code ##
36+
class Foo:
37+
@MyMethod
38+
def do_something(self, value: int) -> None:
39+
...
40+
41+
42+
foo = Foo()
43+
44+
Foo.do_something(foo, 1111)
45+
foo.do_something(1111)
46+
47+
48+
Foo.do_something(1111) # expect-type-error
49+
foo.do_something(11111, foo) # expect-type-error
50+
foo.do_something(foo, 11111) # expect-type-error
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
TODO:
3+
4+
Enhance the Fn[VnCallable].into_callable method to return a Callable with an additional Any parameter at the beginning (using Concatenate).
5+
This should preserve the remaining parts of the function signature from VnCallable (i.e., parameters and their types, excluding the suffix), as well as the return type.
6+
"""
7+
8+
from typing import Callable, TypeVar, Generic, Any, assert_type
9+
10+
VnCallable = TypeVar("VnCallable", bound=Callable)
11+
12+
13+
class Fn(Generic[VnCallable]):
14+
# you MUST NOT modify the Generic defination.
15+
16+
def __init__(self, f: VnCallable) -> None:
17+
self.f = f
18+
19+
def into_callable(self):
20+
# TODO: annotate self parameter, not required to touch the function body.
21+
# NOTE: the test case requires a Any prefix param before VnCallable's parameters.
22+
# information is enough for type checker to infer these types.
23+
...
24+
25+
26+
## End of your code ##
27+
@Fn
28+
def example(a: int, b: str, c: float, *, d: bool = False) -> None:
29+
return
30+
31+
32+
assert_type(example.f(1, "1", 1.0, d=False), None)
33+
34+
a: Any = 11111111
35+
b = example.into_callable()(a, 1, "1", 1.0, d=False)
36+
assert_type(b, None)
37+
38+
example.into_callable()(1, "1", 1.0, d=False) # expect-type-error
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
TODO:
3+
4+
Enhance the Fn[VnCallable].into_callable method to return a Callable with an additional Any parameter at the beginning (using Concatenate).
5+
This should preserve the remaining parts of the function signature from VnCallable (i.e., parameters and their types, excluding the suffix), as well as the return type.
6+
"""
7+
8+
from typing import Callable, Concatenate, ParamSpec, TypeVar, Generic, Any, assert_type
9+
10+
P = ParamSpec("P")
11+
R = TypeVar("R", covariant=True)
12+
VnCallable = TypeVar("VnCallable", bound=Callable)
13+
14+
15+
class Fn(Generic[VnCallable]):
16+
def __init__(self, f: VnCallable) -> None:
17+
self.f = f
18+
19+
def into_callable(self: "Fn[Callable[P, R]]") -> Callable[Concatenate[Any, P], R]:
20+
...
21+
22+
23+
## End of your code ##
24+
@Fn
25+
def example(a: int, b: str, c: float, *, d: bool = False) -> None:
26+
return
27+
28+
29+
assert_type(example.f(1, "1", 1.0, d=False), None)
30+
31+
a: Any = 11111111
32+
b = example.into_callable()(a, 1, "1", 1.0, d=False)
33+
assert_type(b, None)
34+
35+
example.into_callable()(1, "1", 1.0, d=False) # expect-type-error

0 commit comments

Comments
 (0)