Skip to content
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

gh-104050: Add type annotations to sentinels in Argument Clinic #104589

Closed

Conversation

erlend-aasland
Copy link
Contributor

@erlend-aasland erlend-aasland commented May 17, 2023

@erlend-aasland
Copy link
Contributor Author

I get complaints about isinstance checks now. Using type(sentinel) works, but feel insanely clumsy. Surely there must be a better way to do this.

$ mypy Tools/clinic
Tools/clinic/clinic.py:2697: error: Name "Unknown" is not defined  [name-defined]
Tools/clinic/clinic.py:3478: error: Name "Null" is not defined  [name-defined]
Tools/clinic/clinic.py:3632: error: Name "Null" is not defined  [name-defined]
Tools/clinic/clinic.py:3656: error: Name "Null" is not defined  [name-defined]
Found 4 errors in 1 file (checked 2 source files)

@AlexWaygood
Copy link
Member

AlexWaygood commented May 17, 2023

Rather than doing if isinstance(x, Unknown) as the test, you can do if x is unknown. Since unknown is a sentinel value, the identity check is idiomatic.

@erlend-aasland
Copy link
Contributor Author

Rather than doing if isinstance(x, Unknown), you can do if x is unknown. Since unknown is a sentinel value, the identity check is idiomatic.

Doh. Thanks!

@AlexWaygood
Copy link
Member

The usage of NULL seems a little different from the other two, though, so maybe that one does need its own class. (Not sure about that -- I'm unfamiliar with this code!)

E.g. I can't say I fully understand what's going on with the Null usage here:

default_type = (str, Null, NoneType)

@erlend-aasland
Copy link
Contributor Author

Yeah, the NULL usages need a different treatment. I'll have a look later today.

- Fix variable names
- Add NullType
- Fix instance check
@erlend-aasland erlend-aasland marked this pull request as ready for review May 18, 2023 19:44
@erlend-aasland

This comment was marked as outdated.

@@ -73,6 +81,8 @@ def __repr__(self) -> str:
NULL: Final = Sentinels.NULL
unknown: Final = Sentinels.unknown

NullType = type(Sentinels.NULL)
Copy link
Member

@AlexWaygood AlexWaygood May 18, 2023

Choose a reason for hiding this comment

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

Hmm, The type of Sentinels.Null is just Sentinels. For Python enums, all enum members are instances of the enum class. (This is why I was wondering if maybe the Null class should just be left as it is; it maybe needs to be its own class, rather than sharing the same class as the other sentinel values.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, you're right.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps we should amend this instead:

cpython/Tools/clinic/clinic.py

Lines 2605 to 2607 in dcdc90d

# If not None, default must be isinstance() of this type.
# (You can also specify a tuple of types.)
default_type: bltns.type[Any] | tuple[bltns.type[Any], ...] | None = None

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think my approach is fundamentally flawed. This is pretty simple really: we simply want distinct (sentinel) types for default_type and the instance check (🥁).

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if we're in agreement or not (possibly my brain's going fuzzy at the end of a long day 😆), but I think for this PR, I might keep the refactor for unspecified and unknown, but leave Null as it is on main.

Copy link
Member

Choose a reason for hiding this comment

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

Fab, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The annotation for default_type is probably also incorrect.

cpython/Tools/clinic/clinic.py

Lines 2598 to 2607 in dcdc90d

# The Python default value for this parameter, as a Python value.
# Or the magic value "unspecified" if there is no default.
# Or the magic value "unknown" if this value is a cannot be evaluated
# at Argument-Clinic-preprocessing time (but is presumed to be valid
# at runtime).
default: bool | Unspecified = unspecified
# If not None, default must be isinstance() of this type.
# (You can also specify a tuple of types.)
default_type: bltns.type[Any] | tuple[bltns.type[Any], ...] | None = None

Copy link
Member

@AlexWaygood AlexWaygood May 18, 2023

Choose a reason for hiding this comment

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

The annotation for default_type is probably also incorrect.

It looks correct to me based on the comment and usage. But maybe I'm not seeing something. What makes you think it's incorrect?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With a custom converter, you can override pretty much anything (AFAIK), so I think bltns.type[Any] is too narrow. I might be wrong.

Copy link
Member

Choose a reason for hiding this comment

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

The comment indicates that default has to be an instance of default_type if default_type is not None, and isintance(x, Foo) for any given x will fail if Foo is not an instance of type or a tuple of objects which are instances of type

@erlend-aasland erlend-aasland deleted the typed-clinic/sentinels branch May 18, 2023 20:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants