-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Add type annotations to manim.utils.* #3999
Add type annotations to manim.utils.* #3999
Conversation
@JasonGrace2282 Would you take a look at this PR? |
I'll take a look when I find the time. |
__all__ = ["scene_classes_from_file"] | ||
|
||
|
||
def get_module(file_name: Path): | ||
def get_module(file_name: Path) -> types.ModuleType: |
Check notice
Code scanning / CodeQL
Explicit returns mixed with implicit (fall through) returns Note
cf40c7c
to
224db6d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, this is a huge PR! It will take a long time to review. I added 47 comments and I'm not finished yet, but I hope to continue reviewing soon.
A new PR (#4027) has been merged. This renames InternalPoint3D
(the NumPy array) to Point3D
, and Point3D
(anything resembling a 3D point) to Point3DLike
. Something similar happened with the other type aliases. You might wanna take a look at it.
@@ -125,8 +132,8 @@ def prompt_user_for_choice(scene_classes): | |||
|
|||
|
|||
def scene_classes_from_file( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one could be overloaded like this:
@overload
def scene_classes_from_file(
file_path: Path, require_single_scene: bool, full_list: Literal[True]
) -> list[type[Scene]]: ...
@overload
def scene_classes_from_file(
file_path: Path, require_single_scene: Literal[True], full_list: Literal[False] = False
) -> type[Scene]: ...
@overload
def scene_classes_from_file(
file_path: Path, require_single_scene: Literal[False] = False, full_list: Literal[False] = False
) -> list[type[Scene]]: ...
def scene_classes_from_file(
file_path: Path, require_single_scene: bool = False, full_list: bool = False
) -> type[Scene] | list[type[Scene]]:
# the rest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I try the changes that you suggest in module_ops.py
, I get the errors shown below.
I will leave it for now and hope to get some help in resolving it.
manim/utils/module_ops.py:95: error: "Scene" has no attribute "__name__" [attr-defined]
manim/utils/module_ops.py:104: error: "Scene" has no attribute "__name__" [attr-defined]
manim/utils/module_ops.py:113: error: "Scene" has no attribute "__name__" [attr-defined]
manim/utils/module_ops.py:115: error: Incompatible types in assignment (expression has type "Scene", target has type "type[Scene]") [assignment]
manim/utils/module_ops.py:121: error: List comprehension has incompatible type List[type[Scene]]; expected List[Scene] [misc]
manim/utils/module_ops.py:124: error: "Scene" has no attribute "__name__" [attr-defined]
manim/utils/module_ops.py:168: error: Incompatible return value type (got "Scene", expected "type[Scene] | list[type[Scene]]") [return-value]
manim/utils/module_ops.py:169: error: Incompatible return value type (got "list[Scene]", expected "type[Scene] | list[type[Scene]]") [return-value]
Found 8 errors in 1 file (checked 1 source file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I tried myself, everything was OK.
Your errors suggest that you might have used Scene
instead of type[Scene]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Part 2 of 3:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Part 3 of 3:
# Conflicts: # manim/utils/bezier.py
# Conflicts: # manim/utils/docbuild/module_parsing.py
413adfb
to
de80832
Compare
|
||
|
||
def clip(a, min_a, max_a): | ||
class Comparable(Protocol): | ||
def __lt__(self, other: Any) -> bool: ... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
class Comparable(Protocol): | ||
def __lt__(self, other: Any) -> bool: ... | ||
|
||
def __gt__(self, other: Any) -> bool: ... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
@chopan050, thanks for all the comments. I have addressed most of them in the code, as well as rebased the changes on top of the current main branch. |
@overload | ||
def scene_classes_from_file( | ||
file_path: Path, require_single_scene: bool, full_list: Literal[True] | ||
) -> list[type[Scene]]: ... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
file_path: Path, | ||
require_single_scene: Literal[True], | ||
full_list: Literal[False] = False, | ||
) -> type[Scene]: ... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
file_path: Path, | ||
require_single_scene: Literal[False] = False, | ||
full_list: Literal[False] = False, | ||
) -> list[type[Scene]]: ... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
since: str | None = None, | ||
until: str | None = None, | ||
replacement: str | None = None, | ||
message: str | None = "", | ||
) -> Callable: | ||
) -> Callable[..., T]: ... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
until: str | None = None, | ||
replacement: str | None = None, | ||
message: str | None = "", | ||
) -> Callable[[Callable[..., T]], Callable[..., T]]: ... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! This has been a huge effort, and we really appreciate it! Thank you so much!
If you don't mind, I pushed some changes in order to finish this PR:
- I removed
caching
,polylabel
andqhull
frommypy.ini
after fixing some MyPy errors there. I couldn't, however, removehashing
because it was way too complex to type. Still, this means that almost all ofutils
is typed, which is great! manim.utils.module_ops
could usetype[Scene]
, as I mentioned in a comment.- I rewrote that function in
manim.utils.rate_functions
which usedbezier
, because MyPy wouldn't stop complaining about that. - I realized that
ParamSpec
was introduced in Python 3.10 and we're still supporting Python 3.9. Therefore, I had to modify the changes where I suggested usingParamSpec
. In the future, when we drop support for Python 3.9, we would apply it. - It turns out that the dir properties in
ManimConfig
always returnstr
, because they're always converted tostr
when you attempt to set them. MyPy, however, dislikes that the getter returns astr
and the setter accepts astr | Path
to convert it tostr
, so this is something which must be fixed in a subsequent PR. In the meantime, I had to use some# type: ignore
comments to silence it. - I fixed some other MyPy errors.
Overview: What does this pull request change?
The PR adds type annotations to some of the elements in manim/utils
Motivation and Explanation: Why and how do your changes improve the library?
Type annotations are a good thing.
Further Information and Comments
I have chosen to go for smaller PR regarding adding type annotations.
The endeavor of #3981 is a bit frightening...
Reviewer Checklist