Skip to content

Conversation

@vincentmacri
Copy link
Member

@vincentmacri vincentmacri commented Oct 27, 2025

Replace things like List[T] with list[T] in type annotations. Enables this rule in CI and in configuration files.

To do this I used ruff to fix UP006, then fixed F401 on the changed files (to remove the UP006 unused imports left behind by UP006).

There are several other ruff UP rules that have autofix and can easily be enabled. To keep the PR a reasonable size we only do UP006 here.

📝 Checklist

  • The title is concise and informative.
  • The description explains in detail what this PR is about.
  • I have linked a relevant issue or discussion.
  • I have created tests covering the changes.
  • I have updated the documentation and checked the documentation preview.

@vincentmacri vincentmacri added t: refactoring github_actions Pull requests that update GitHub Actions code labels Oct 27, 2025
# 2 PLE0302 [ ] The special method `__len__` expects 1 parameter, 3 were given
# 1 F402 [ ] Import `factor` from line 259 shadowed by loop variable
# 1 PLC0208 [*] Use a sequence type instead of a `set` when iterating over values
# 10589 PLC0415 [ ] import-outside-top-level
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this comment while I was touching this file. Looks like that hasn't been done in a while.

pyproject.toml Outdated
[tool.ruff.lint]
ignore = [
"E501", # Line too long - hard to avoid in doctests, and better handled by black.
"UP045", # non-pep604-annotation-optional - Whether `Optional[T]` or `T | None` is better is subjective.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In preparation for eventually being able to enable more/all UP rules. At first glance this was the only one I saw that seemed potentially controversial. I'm not taking a stance on it for this PR, but my personal opinion is that Optional is more readable for parameters and less readable for return values.

Other rules in UP that would have a big impact for us: changing old-style string formatting to f-strings. I think that's only an issue for us because of how many files it would change. In principle I think f-strings are far more readable, but unless we want to do a patch bomb it's hard to see us ever transitioning the entire code base to f-strings. (I guess in theory we could do some kind of git hook autoformat when files get changed for other reasons to slowly transition things over automatically, but I think that would be controversial.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think

def func(param: str | None = None)

is clearer and involves less mental overhead to understand than having param: Optional[str] = None.

@github-actions
Copy link

github-actions bot commented Oct 27, 2025

Documentation preview for this PR (built with commit 4e3f7c9; changes) is ready! 🎉
This preview will update shortly after each push to this PR.

@vincentmacri vincentmacri changed the title Fix and enable ruff UP006 Fix and enable ruff UP006 (simplify typing annotations) Nov 4, 2025
@vincentmacri vincentmacri changed the title Fix and enable ruff UP006 (simplify typing annotations) Simplify typing annotations (ruff UP006) Nov 4, 2025
Copy link
Contributor

@tobiasdiez tobiasdiez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nitpicks

...

def list(self) -> List:
def list(self) -> builtins.list:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not simply list?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was made by ruff. I think the reason it is using builtins is because (as seen on this line) there is a function called list which ruff thinks is overwriting the builtin name. I'll remove the builtins and see what happens (if there is an error I'll revert).

...

def _im_gens_(self, codomain: Any, im_gens: List[Any], base_map: Optional[Any] = None) -> 'LaurentSeriesRingElement':
def _im_gens_(self, codomain: Any, im_gens: builtins.list[Any], base_map: Optional[Any] = None) -> 'LaurentSeriesRingElement':
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here in this file a couple of times

pyproject.toml Outdated
[tool.ruff.lint]
ignore = [
"E501", # Line too long - hard to avoid in doctests, and better handled by black.
"UP045", # non-pep604-annotation-optional - Whether `Optional[T]` or `T | None` is better is subjective.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think

def func(param: str | None = None)

is clearer and involves less mental overhead to understand than having param: Optional[str] = None.

@vincentmacri
Copy link
Member Author

I think

def func(param: str | None = None)

is clearer and involves less mental overhead to understand than having param: Optional[str] = None.

As I said, this one is more of a matter of opinion than a strict style rule. Unlike Optional, List et al. are eventually supposed to be deprecated.

While I personally like Optional, I won't oppose if someone else wants to change Optional[str] to str | None. I'll remove this explicit ignore line for now.

The reason I like Optional is I think it's more clear to someone who isn't familiar with Python type annotation syntax.

@tobiasdiez
Copy link
Contributor

I think
def func(param: str | None = None)
is clearer and involves less mental overhead to understand than having param: Optional[str] = None.

As I said, this one is more of a matter of opinion than a strict style rule. Unlike Optional, List et al. are eventually supposed to be deprecated.

While I personally like Optional, I won't oppose if someone else wants to change Optional[str] to str | None. I'll remove this explicit ignore line for now.

The reason I like Optional is I think it's more clear to someone who isn't familiar with Python type annotation syntax.

I also don't really care too much. After a bit of digging, I found python/cpython#30222 (review) which does state that the shorthand version is preferred. I would suggest we just choose one way, and than use that consistently.

@vincentmacri
Copy link
Member Author

I think
def func(param: str | None = None)
is clearer and involves less mental overhead to understand than having param: Optional[str] = None.

As I said, this one is more of a matter of opinion than a strict style rule. Unlike Optional, List et al. are eventually supposed to be deprecated.
While I personally like Optional, I won't oppose if someone else wants to change Optional[str] to str | None. I'll remove this explicit ignore line for now.
The reason I like Optional is I think it's more clear to someone who isn't familiar with Python type annotation syntax.

I also don't really care too much. After a bit of digging, I found python/cpython#30222 (review) which does state that the shorthand version is preferred. I would suggest we just choose one way, and than use that consistently.

| is preferred to Union, but Optional I think is a special case where either is considered fine as long as we are consistent (this is why ruff has these are different rules). I think ruff can autofix Optional to | None so we probably just turn on that rule later as having autofix is kind of necessary for being consistent on a codebase as large as Sage.

Either way, this is a different rule in ruff than the rule this PR is fixing. So it's something to think about for followup work. I didn't want to submit a patch bomb (@fchapoton requested on one of my previous PRs that I split things up better) so I plan to submit a series of PRs enabling a handful of ruff rules at a time. Next will probably be fixing implicit Optional since that's an actual error. Maybe I'll change Optional to | None at the same time if it doesn't make the patch too big. After that maybe getting rid of Union since | is preferred as you pointed out.

@vincentmacri
Copy link
Member Author

Thanks for the review!

@vincentmacri
Copy link
Member Author

vincentmacri commented Nov 5, 2025

I'm assuming from you marking this as approved changes that you meant to set the positive review label, please change the label back if not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

github_actions Pull requests that update GitHub Actions code s: positive review t: refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants