Skip to content

[maintainers] why is test_models.py throwing an error for dj40 locally but not in GH actions? #1165

@n2ygk

Description

@n2ygk

When I run tox locally for dj40, I see an error due to referencing model instance pk (which makes sense based on reading the code) but I don't see the same error when it is run in GitHub Actions where the py39-dj40 log is clean.

Here's a portion of local execution:

django-oauth-toolkit$ tox -e py39-dj40 tests/test_models.py::TestClearExpired::test_clear_expired_tokens_with_tokens
GLOB sdist-make: /Users/ac45/src/django-oauth-toolkit/setup.py
py39-dj40 inst-nodeps: /Users/ac45/src/django-oauth-toolkit/.tox/.tmp/package/1/django-oauth-toolkit-2.0.0.zip
py39-dj40 installed: asgiref==3.5.2,attrs==21.4.0,certifi==2022.5.18.1,cffi==1.15.0,charset-normalizer==2.0.12,coverage==6.4,cryptography==37.0.2,Deprecated==1.2.13,Django==4.0.4,django-oauth-toolkit==2.0.0,djangorestframework==3.13.1,execnet==1.9.0,idna==3.3,iniconfig==1.1.1,jwcrypto==1.3.1,oauthlib==3.2.0,packaging==21.3,pluggy==1.0.0,py==1.11.0,pycparser==2.21,pyparsing==3.0.9,pytest==7.1.2,pytest-cov==3.0.0,pytest-django==4.5.2,pytest-forked==1.4.0,pytest-mock==3.7.0,pytest-xdist==2.5.0,pytz==2022.1,requests==2.27.1,sqlparse==0.4.2,tomli==2.0.1,urllib3==1.26.9,wrapt==1.14.1
py39-dj40 run-test-pre: PYTHONHASHSEED='2725533432'
py39-dj40 run-test: commands[0] | pytest tests/test_models.py::TestClearExpired::test_clear_expired_tokens_with_tokens
======================================================== test session starts ========================================================
platform darwin -- Python 3.9.11, pytest-7.1.2, pluggy-1.0.0
cachedir: .tox/py39-dj40/.pytest_cache
django: settings: tests.settings (from env)
rootdir: /Users/ac45/src/django-oauth-toolkit, configfile: tox.ini
plugins: xdist-2.5.0, forked-1.4.0, mock-3.7.0, django-4.5.2, cov-3.0.0
collected 1 item                                                                                                                    

tests/test_models.py F

============================================================= FAILURES ==============================================================
______________________________________ TestClearExpired.test_clear_expired_tokens_with_tokens _______________________________________

self = <tests.test_models.TestClearExpired testMethod=test_clear_expired_tokens_with_tokens>

    def setUp(self):
        super().setUp()
        # Insert many tokens, both expired and not, and grants.
        self.num_tokens = 100
        now = timezone.now()
        earlier = now - timedelta(seconds=100)
        later = now + timedelta(seconds=100)
        app = Application.objects.create(
            name="test_app",
            redirect_uris="http://localhost http://example.com http://example.org",
            user=self.user,
            client_type=Application.CLIENT_CONFIDENTIAL,
            authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
        )
        # make 200 access tokens, half current and half expired.
        expired_access_tokens = AccessToken.objects.bulk_create(
            AccessToken(token="expired AccessToken {}".format(i), expires=earlier)
            for i in range(self.num_tokens)
        )
        current_access_tokens = AccessToken.objects.bulk_create(
            AccessToken(token=f"current AccessToken {i}", expires=later) for i in range(self.num_tokens)
        )
        # Give the first half of the access tokens a refresh token,
        # alternating between current and expired ones.
>       RefreshToken.objects.bulk_create(
            RefreshToken(
                token=f"expired AT's refresh token {i}",
                application=app,
                access_token=expired_access_tokens[i].pk,
                user=self.user,
            )
            for i in range(0, len(expired_access_tokens) // 2, 2)
        )

tests/test_models.py:321: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py39-dj40/lib/python3.9/site-packages/django/db/models/manager.py:85: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
.tox/py39-dj40/lib/python3.9/site-packages/django/db/models/query.py:559: in bulk_create
    objs = list(objs)
tests/test_models.py:322: in <genexpr>
    RefreshToken(
.tox/py39-dj40/lib/python3.9/site-packages/django/db/models/base.py:541: in __init__
    _setattr(self, field.name, rel_obj)
.tox/py39-dj40/lib/python3.9/site-packages/django/db/models/fields/related_descriptors.py:338: in __set__
    super().__set__(instance, value)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <django.db.models.fields.related_descriptors.ForwardOneToOneDescriptor object at 0x109e0b160>
instance = <RefreshToken: expired AT's refresh token 0>, value = 1

    def __set__(self, instance, value):
        """
        Set the related instance through the forward relation.
    
        With the example above, when setting ``child.parent = parent``:
    
        - ``self`` is the descriptor managing the ``parent`` attribute
        - ``instance`` is the ``child`` instance
        - ``value`` is the ``parent`` instance on the right of the equal sign
        """
        # An object must be an instance of the related class.
        if value is not None and not isinstance(
            value, self.field.remote_field.model._meta.concrete_model
        ):
>           raise ValueError(
                'Cannot assign "%r": "%s.%s" must be a "%s" instance.'
                % (
                    value,
                    instance._meta.object_name,
                    self.field.name,
                    self.field.remote_field.model._meta.object_name,
                )
E               ValueError: Cannot assign "1": "RefreshToken.access_token" must be a "AccessToken" instance.

.tox/py39-dj40/lib/python3.9/site-packages/django/db/models/fields/related_descriptors.py:235: ValueError

Looking in, for example, this execution log all the tests pass.

@Andrew-Chen-Wang the only environmental difference I can see is that sqlite3 version is 3.31 on GH and 3.37 locally.

Related is it appears the error wasn't being logged in earlier Django release because the value of pk is None?? This is what I see when debugging under PyCharm. I think I may just revert the bulk_create which doesn't do a save. It's all an in-memory DB anyway so it's not a huge performance win.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions