Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0e53252
fix(deps): update dependency ty to v0.0.1a25
renovate[bot] Nov 7, 2025
2016eef
Initial plan
Copilot Nov 7, 2025
404c1dc
Fix type check errors for ty v0.0.1a25
Copilot Nov 7, 2025
810b8b6
Fix remaining type check errors for ty v0.0.1a25
Copilot Nov 7, 2025
2e58511
Improve comment clarity in open_id.py
Copilot Nov 7, 2025
ae20876
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 7, 2025
beb42bb
Replace _Base pattern with Protocol for type checking
Copilot Nov 7, 2025
53f0c87
Make mixins inherit from Protocol during TYPE_CHECKING
Copilot Nov 7, 2025
fc82ba8
Changes before error encountered
Copilot Nov 7, 2025
09630fa
Share OAuth2TestProtocol across all test files
Copilot Nov 7, 2025
6ee6663
Improve type annotations in OAuth2TestProtocol
Copilot Nov 10, 2025
a83cca2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 10, 2025
5164e4f
Fix cast() call broken by pre-commit autofix
Copilot Nov 10, 2025
eaf9c84
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 10, 2025
f137f4f
Fix cast() again and add noqa to prevent pre-commit changes
Copilot Nov 10, 2025
3600f1c
Revert to cast("Any", ...) - string form is correct
Copilot Nov 10, 2025
a7573b2
Replace cast() with type: ignore comment for Mock assignment
Copilot Nov 10, 2025
939725d
Remove Protocol inheritance from mixins to fix MRO issues
Copilot Nov 10, 2025
d66e21d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 10, 2025
99d802b
Use Protocol properly with TYPE_CHECKING conditional inheritance
Copilot Nov 10, 2025
7aa612b
fix(deps): update dependency ty to v0.0.1a26
renovate[bot] Nov 11, 2025
bf66726
Merge branch 'renovate/ty-0.x' into copilot/sub-pr-1382
nijel Nov 11, 2025
84ab57c
Add extra_settings and auth_handlers to OAuth2TestProtocol
Copilot Nov 11, 2025
34dfdd7
Add extra_data type annotation to TestUserSocialAuth
Copilot Nov 11, 2025
65dccf3
Remove extra_data override annotation from TestUserSocialAuth
Copilot Nov 12, 2025
c410943
Add assertion for extra_data type narrowing in tests
Copilot Nov 12, 2025
5de7184
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dev = [
"pytest-xdist==3.8.0",
"pytest==9.0.0",
"responses==0.25.8",
"ty==0.0.1a23",
"ty==0.0.1a26",
"types-defusedxml==0.7.0.20250822",
"types-oauthlib==3.3.0.20250822",
"types-requests-oauthlib==2.0.0.20250809",
Expand Down Expand Up @@ -84,7 +84,7 @@ dev = [
"pytest-xdist==3.8.0",
"pytest==9.0.0",
"responses==0.25.8",
"ty==0.0.1a23",
"ty==0.0.1a26",
"types-defusedxml==0.7.0.20250822",
"types-oauthlib==3.3.0.20250822",
"types-requests-oauthlib==2.0.0.20250809",
Expand Down
2 changes: 1 addition & 1 deletion social_core/backends/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def extra_data(
elif len(entry) == 3:
name, alias, discard = entry
elif len(entry) == 2:
name, alias = entry
name, alias = entry # type: ignore[misc]
elif len(entry) == 1:
name = alias = entry[0]
else:
Expand Down
2 changes: 1 addition & 1 deletion social_core/backends/oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ def refresh_token(self, token, *args, **kwargs):
method = self.REFRESH_TOKEN_METHOD
key = "params" if method == "GET" else "data"
request_args = {"headers": self.auth_headers(), "method": method, key: params}
request = self.request(url, **request_args)
request = self.request(url, **request_args) # type: ignore[arg-type]
return self.process_refresh_token_response(request, *args, **kwargs)

def refresh_token_url(self):
Expand Down
2 changes: 1 addition & 1 deletion social_core/backends/vk.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@
if user_check == 1:
is_user = self.data.get("is_app_user")
elif user_check == 2:
is_user = self.vk_api("isAppUser", {"user_id": user_id}).get(

Check warning on line 199 in social_core/backends/vk.py

View workflow job for this annotation

GitHub Actions / types

ty (possibly-missing-attribute)

social_core/backends/vk.py:199:27: possibly-missing-attribute: Attribute `get` may be missing on object of type `dict[Any, Any] | None`

Check warning on line 199 in social_core/backends/vk.py

View workflow job for this annotation

GitHub Actions / types

ty (possibly-missing-attribute)

social_core/backends/vk.py:199:27: possibly-missing-attribute: Attribute `get` may be missing on object of type `dict[Any, Any] | None`
"response", 0
)
if not int(is_user):
Expand All @@ -210,7 +210,7 @@
self.id_key(): user_id,
},
}
auth_data["response"].update(

Check warning on line 213 in social_core/backends/vk.py

View workflow job for this annotation

GitHub Actions / types

ty (possibly-missing-attribute)

social_core/backends/vk.py:213:9: possibly-missing-attribute: Attribute `update` may be missing on object of type `Unknown | Self@auth_complete | dict[Unknown | str, Unknown]`

Check warning on line 213 in social_core/backends/vk.py

View workflow job for this annotation

GitHub Actions / types

ty (possibly-missing-attribute)

social_core/backends/vk.py:213:9: possibly-missing-attribute: Attribute `update` may be missing on object of type `Unknown | Self@auth_complete | dict[Unknown | str, Unknown]`
json.loads(auth_data["request"]["api_result"])["response"][0]
json.loads(auth_data["request"]["api_result"])["response"][0] # type: ignore[index]
)
return self.strategy.authenticate(*args, **auth_data)
4 changes: 3 additions & 1 deletion social_core/backends/yahoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ def refresh_token(self, token, *args, **kwargs):
key = "params" if method == "GET" else "data"
request_args = {"headers": self.auth_headers(), "method": method, key: params}
request = self.request(
url, auth=HTTPBasicAuth(*self.get_key_and_secret()), **request_args
url,
auth=HTTPBasicAuth(*self.get_key_and_secret()),
**request_args, # type: ignore[arg-type]
)
return self.process_refresh_token_response(request, *args, **kwargs)

Expand Down
2 changes: 1 addition & 1 deletion social_core/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def get_backend(
) -> BaseAuth:
"""Return a configured backend instance"""
Backend = self.get_backend_class(name)
return Backend(self, *args, redirect_uri=redirect_uri, **kwargs)
return Backend(self, *args, redirect_uri=redirect_uri, **kwargs) # type: ignore[misc]

# Implement the following methods on strategies sub-classes

Expand Down
43 changes: 42 additions & 1 deletion social_core/tests/backends/oauth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Generic, TypeVar, cast
from typing import TYPE_CHECKING, Generic, Protocol, TypeVar, cast
from unittest.mock import patch
from urllib.parse import urlparse

Expand All @@ -13,9 +13,50 @@

from .base import BaseBackendTest

if TYPE_CHECKING:
from social_core.tests.models import TestUserSocialAuth

OAuthBackendT = TypeVar("OAuthBackendT", bound=OAuthAuth)


class OAuth2TestProtocol(Protocol):
"""Protocol for OAuth2 test methods used by mixins.

This protocol defines the interface that OAuth2 test mixins expect
from test base classes. It includes common unittest.TestCase methods
and OAuth2-specific test helper methods.
"""

def assertEqual(self, first: object, second: object, msg: object = None) -> None:
"""Assert that two values are equal."""
...

def do_login(self) -> User:
"""Perform a login flow and return the user."""
...

def do_partial_pipeline(self) -> User:
"""Perform a partial pipeline flow and return the user."""
...

def do_refresh_token(self) -> tuple[User, TestUserSocialAuth]:
"""Perform a token refresh flow and return user and social auth."""
...

def extra_settings(self) -> dict[str, str | list[str]]:
"""Return extra settings for the backend."""
...

def auth_handlers(self, start_url: str) -> str:
"""Handle authentication flow and return target URL."""
...

@property
def name(self) -> str:
"""Backend name for settings."""
...


class BaseOAuthTest(BaseBackendTest[OAuthBackendT], Generic[OAuthBackendT]):
user_data_body: str | None = None
user_data_url: str = ""
Expand Down
4 changes: 4 additions & 0 deletions social_core/tests/backends/open_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ def handle_starttag(self, tag, attrs) -> None:


class OpenIdTest(BaseBackendTest):
# These attributes must be defined by subclasses
discovery_body: str
server_response: str

def setUp(self) -> None:
responses.start()
Backend = module_member(self.backend_path)
Expand Down
12 changes: 9 additions & 3 deletions social_core/tests/backends/test_bitbucket_datacenter.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
# pyright: reportAttributeAccessIssue=false

import json
from typing import TYPE_CHECKING

import responses

from .oauth import OAuth2PkcePlainTest, OAuth2PkceS256Test

if TYPE_CHECKING:
from .oauth import OAuth2TestProtocol

_Base = OAuth2TestProtocol
else:
_Base = object


class BitbucketDataCenterOAuth2Mixin:
class BitbucketDataCenterOAuth2Mixin(_Base): # type: ignore[misc]
backend_path = "social_core.backends.bitbucket_datacenter.BitbucketDataCenterOAuth2"
application_properties_url = (
"https://bachmanity.atlassian.net/rest/api/latest/application-properties"
Expand Down Expand Up @@ -86,20 +92,20 @@

social = user.social[0]
self.assertEqual(social.uid, "1")
self.assertEqual(social.extra_data["first_name"], "Erlich")

Check failure on line 95 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:95:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 95 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:95:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
self.assertEqual(social.extra_data["last_name"], "Bachman")

Check failure on line 96 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:96:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 96 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:96:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
self.assertEqual(social.extra_data["email"], "[email protected]")

Check failure on line 97 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:97:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 97 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:97:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
self.assertEqual(social.extra_data["name"], "erlich-bachman")

Check failure on line 98 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:98:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 98 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:98:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
self.assertEqual(social.extra_data["username"], "erlich-bachman")

Check failure on line 99 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:99:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 99 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:99:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
self.assertEqual(social.extra_data["display_name"], "Erlich Bachman")

Check failure on line 100 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:100:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 100 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:100:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
self.assertEqual(social.extra_data["type"], "NORMAL")

Check failure on line 101 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:101:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 101 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:101:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
self.assertEqual(social.extra_data["active"], True)

Check failure on line 102 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:102:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 102 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:102:26: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
self.assertEqual(
social.extra_data["url"],

Check failure on line 104 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:104:13: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 104 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:104:13: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
"https://bachmanity.atlassian.net/users/erlich-bachman",
)
self.assertEqual(
social.extra_data["avatar_url"],

Check failure on line 108 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:108:13: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method

Check failure on line 108 in social_core/tests/backends/test_bitbucket_datacenter.py

View workflow job for this annotation

GitHub Actions / types

ty (non-subscriptable)

social_core/tests/backends/test_bitbucket_datacenter.py:108:13: non-subscriptable: Cannot subscript object of type `None` with no `__getitem__` method
"http://www.gravatar.com/avatar/af7d968fe79ea45271e3100391824b79.jpg?s=48&d=mm",
)
self.assertEqual(social.extra_data["scope"], "PUBLIC_REPOS")
Expand Down
12 changes: 9 additions & 3 deletions social_core/tests/backends/test_etsy.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# pyright: reportAttributeAccessIssue=false

import json
from typing import TYPE_CHECKING

from .oauth import OAuth2PkceS256Test

if TYPE_CHECKING:
from .oauth import OAuth2TestProtocol

_Base = OAuth2TestProtocol
else:
_Base = object


class EtsyOAuth2Mixin:
class EtsyOAuth2Mixin(_Base): # type: ignore[misc]
backend_path = "social_core.backends.etsy.EtsyOAuth2"
access_token_body = json.dumps(
{
Expand Down
12 changes: 9 additions & 3 deletions social_core/tests/backends/test_twitter_oauth2.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# pyright: reportAttributeAccessIssue=false

import json
from typing import TYPE_CHECKING

from social_core.exceptions import AuthException

Expand All @@ -11,8 +10,15 @@
OAuth2Test,
)

if TYPE_CHECKING:
from .oauth import OAuth2TestProtocol

_Base = OAuth2TestProtocol
else:
_Base = object


class TwitterOAuth2Mixin:
class TwitterOAuth2Mixin(_Base): # type: ignore[misc]
backend_path = "social_core.backends.twitter_oauth2.TwitterOAuth2"
user_data_url = "https://api.twitter.com/2/users/me"
access_token_body = json.dumps(
Expand Down
2 changes: 2 additions & 0 deletions social_core/tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ def __init__(self, user: User, provider, uid, extra_data=None) -> None:
self.provider = provider
self.uid = uid
self.extra_data = extra_data or {}
# Type narrowing: extra_data is always a dict in tests, never None
assert self.extra_data is not None
self.user.social.append(self)
TestUserSocialAuth.cache_by_uid[uid] = self

Expand Down
3 changes: 2 additions & 1 deletion social_core/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ def _backend(self, session_kwargs=None):
class GetKeyAndSecretBasicAuthTest(unittest.TestCase):
def setUp(self) -> None:
self.backend = BaseAuth(strategy=Mock())
self.backend.setting = Mock(
# Assign Mock to setting method, bypassing type checking for this dynamic replacement
self.backend.setting = Mock( # type: ignore[method-assign]
side_effect=lambda x: "test_key" if x == "KEY" else "test_secret"
)

Expand Down
Loading