Skip to content

Commit

Permalink
Add some challenges (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
GreyElaina authored Dec 10, 2023
1 parent 42a9818 commit 535c1f2
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 0 deletions.
38 changes: 38 additions & 0 deletions challenges/advanced-descriptor-basic/question.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
TODO:
Create a descriptor and adorn the __get__ method with the @typing.overload decorator to ensure the functionality of the test case.
NOTE: Craft at least two overload declarations:
- one to handle the case when the instance is None (i.e., accessing TestClass.a), and another...
- ...to cater to any instance of TestClass.
NOTE: By explicitly binding the instance parameter to the TestClass class, the test cases can also be successfully passed.
"""


class Descriptor:
def __get__(self, instance: ..., owner: ...):
"""you don't need to implement this"""
...


## End of your code ##
class TestClass:
a = Descriptor()


def descriptor_self(x: Descriptor) -> None:
...


def string_value(x: str) -> None:
...


descriptor_self(TestClass.a)
string_value(TestClass().a)

descriptor_self(TestClass().a) # expect-type-error
string_value(TestClass.a) # expect-type-error
43 changes: 43 additions & 0 deletions challenges/advanced-descriptor-basic/solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
TODO:
Define a descriptor, make test case works.
"""

from typing import overload, Self, Any


class Descriptor:
@overload
def __get__(self, instance: None, owner: type) -> Self:
...

@overload
def __get__(self, instance: Any, owner: type) -> str:
...

def __get__(self, instance: Any, owner: type) -> Self | str:
if instance is None:
return self

return ""


## End of your code ##
class TestClass:
a = Descriptor()


def descriptor_self(x: Descriptor) -> None:
...


def string_value(x: str) -> None:
...


descriptor_self(TestClass.a)
string_value(TestClass().a)

descriptor_self(TestClass().a) # expect-type-error
string_value(TestClass.a) # expect-type-error
36 changes: 36 additions & 0 deletions challenges/advanced-my-method/question.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
TODO:
a method-like descriptor, implements the `__get__` only.
"""
from typing import ParamSpec, TypeVar, Concatenate, Callable, Generic

P = ParamSpec("P")
T = TypeVar("T")
R = TypeVar("R")


class MyMethod(Generic[T, P, R]):
def __init__(self, func: Callable[Concatenate[T, P], R]) -> None:
self.func = func

def __get__(self, instance, owner) -> None:
return


## End of your code ##
class Foo:
@MyMethod
def do_something(self, value: int) -> None:
...


foo = Foo()

Foo.do_something(foo, 1111)
foo.do_something(1111)


Foo.do_something(1111) # expect-type-error
foo.do_something(11111, foo) # expect-type-error
foo.do_something(foo, 11111) # expect-type-error
50 changes: 50 additions & 0 deletions challenges/advanced-my-method/solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
TODO:
a method-like descriptor, implements the `__get__` only.
"""
from typing import Any, ParamSpec, TypeVar, Concatenate, Callable, Generic, overload

P = ParamSpec("P")
T = TypeVar("T")
R = TypeVar("R")


class MyMethod(Generic[T, P, R]):
def __init__(self, func: Callable[Concatenate[T, P], R]) -> None:
self.func = func

@overload
def __get__(self, instance: None, owner: type) -> Callable[Concatenate[T, P], R]:
...

@overload
def __get__(self, instance: Any, owner: type) -> Callable[P, R]:
...

def __get__(self, instance: Any | None, owner: type):
if instance is None:
return self.func

def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
return self.func(instance, *args, **kwargs)

return wrapper


## End of your code ##
class Foo:
@MyMethod
def do_something(self, value: int) -> None:
...


foo = Foo()

Foo.do_something(foo, 1111)
foo.do_something(1111)


Foo.do_something(1111) # expect-type-error
foo.do_something(11111, foo) # expect-type-error
foo.do_something(foo, 11111) # expect-type-error
38 changes: 38 additions & 0 deletions challenges/extreme-self-casting/question.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
TODO:
Enhance the Fn[VnCallable].into_callable method to return a Callable with an additional Any parameter at the beginning (using Concatenate).
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.
"""

from typing import Callable, TypeVar, Generic, Any, assert_type

VnCallable = TypeVar("VnCallable", bound=Callable)


class Fn(Generic[VnCallable]):
# you MUST NOT modify the Generic defination.

def __init__(self, f: VnCallable) -> None:
self.f = f

def into_callable(self):
# TODO: annotate self parameter, not required to touch the function body.
# NOTE: the test case requires a Any prefix param before VnCallable's parameters.
# information is enough for type checker to infer these types.
...


## End of your code ##
@Fn
def example(a: int, b: str, c: float, *, d: bool = False) -> None:
return


assert_type(example.f(1, "1", 1.0, d=False), None)

a: Any = 11111111
b = example.into_callable()(a, 1, "1", 1.0, d=False)
assert_type(b, None)

example.into_callable()(1, "1", 1.0, d=False) # expect-type-error
35 changes: 35 additions & 0 deletions challenges/extreme-self-casting/solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
TODO:
Enhance the Fn[VnCallable].into_callable method to return a Callable with an additional Any parameter at the beginning (using Concatenate).
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.
"""

from typing import Callable, Concatenate, ParamSpec, TypeVar, Generic, Any, assert_type

P = ParamSpec("P")
R = TypeVar("R", covariant=True)
VnCallable = TypeVar("VnCallable", bound=Callable)


class Fn(Generic[VnCallable]):
def __init__(self, f: VnCallable) -> None:
self.f = f

def into_callable(self: "Fn[Callable[P, R]]") -> Callable[Concatenate[Any, P], R]:
...


## End of your code ##
@Fn
def example(a: int, b: str, c: float, *, d: bool = False) -> None:
return


assert_type(example.f(1, "1", 1.0, d=False), None)

a: Any = 11111111
b = example.into_callable()(a, 1, "1", 1.0, d=False)
assert_type(b, None)

example.into_callable()(1, "1", 1.0, d=False) # expect-type-error

0 comments on commit 535c1f2

Please sign in to comment.