Skip to content

Annotate resource_server as str for some cases - #1414

Merged
sirosen merged 1 commit into
globus:mainfrom
sirosen:improve-resource-server-annotations
Aug 6, 2026
Merged

Annotate resource_server as str for some cases#1414
sirosen merged 1 commit into
globus:mainfrom
sirosen:improve-resource-server-annotations

Conversation

@sirosen

@sirosen sirosen commented Aug 5, 2026

Copy link
Copy Markdown
Member

Several classes set scopes as a class attribute, meaning that their resource_server class property will evaluate to str, rather than str | None.
Technically, this can be violated (if scopes is deleted from the class), but in terms of a closed system of type-safe code, the annotation is correct.

An annotation without an assignment does not rebind the name, so the subclasses' resource_server attribute still points at the classproperty descriptor.

This corrects several type-checking errors in the docs without requiring improper checks or type-ignores to provide type-safety.

Several classes set `scopes` as a class attribute, meaning that their
`resource_server` class property will evaluate to `str`, rather than
`str | None`. _Technically_, this can be violated (if `scopes` is
deleted from the class), but in terms of a closed system of type-safe
code, the annotation is correct.

An annotation without an assignment does not rebind the name, so the
subclasses' `resource_server` attribute still points at the classproperty
descriptor.

This corrects several type-checking errors in the docs without requiring
improper checks or type-ignores to provide type-safety.
@sirosen sirosen added the no-news-is-good-news This change does not require a news file label Aug 5, 2026

@derek-globus derek-globus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm surprised that this narrowing is type-safe, but our CI linting demonstrates that it is.

@sirosen

sirosen commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

I was also surprised to see it work when I tried it! 😅
I expected to need type-ignore comments.

A simplified form also works:

class A:
    x: int | str

class B(A):
    x: int

reveal_type(B.x)  # int!

It's unquestionably a soundness hole in typing, but there are lots of those, so I'm not that surprised.

other bad soundness hole tangent

There are worse things! For example, early on float was treated as meaning float | int. This still holds today!

def f(x: float) -> None:
    pass

y: int = 0

# type-checks okay! :,(
f(y)

It's wrong! Many things which take floats also take ints, but not all. There are C APIs which need a float. 💀

And any protocol or superclass annotation which attempts to restrict the methods you use can be circumvented by the narrowing in an isinstance check. For example:

class P:
    def plus1(self, x: int) -> int:
        return x + 1

class C(P):
    def __init__(self) -> None:
        self.counter = 0

    def incr(self, x: int) -> int:
        self.counter += x
        return self.counter

def only_use_mutation_free_methods(obj: P, x: int) -> int:
    ...  # 70 lines of code go here
    if isinstance(obj, C):
        y = obj.incr(x)
    else:
        y = obj.plus1(x)
    ...  # 30 more lines of code
    return y

That means that even if you annotate it Iterable, I can make it list, and if it's Mapping (rather than MutableMapping), I can make it dict. 💀

But it still works well enough to be useful! Mostly.

@sirosen
sirosen merged commit 8f986b4 into globus:main Aug 6, 2026
10 checks passed
@sirosen
sirosen deleted the improve-resource-server-annotations branch August 6, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-news-is-good-news This change does not require a news file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants