Account for posts in optimizer
Commit 9e3fa pushed by Anže Pečar

15 tests 11 passed 4 failed Duration
self = <stats.tests.TestStats testMethod=test_all_daily_lang_stats>

    def test_all_daily_lang_stats(self):
        for lang in LANGUAGES:
>           self.assertTrue(
                hasattr(Daily, lang.code + "_accounts"),
                f"{lang.code} missing from Daily model.",
            )
E           AssertionError: False is not true : rstats missing from Daily model.

stats/tests.py:15: AssertionError
self = <QuerySet []>
defaults = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}

    def get_or_create(self, defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, creating one if necessary.
        Return a tuple of (object, created), where created is a boolean
        specifying whether an object was created.
        """
        # The get() needs to be targeted at the write database in order
        # to avoid potential transaction consistency problems.
        self._for_write = True
        try:
>           return self.get(**kwargs), False

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:948: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet []>, args = ()
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}
clone = <QuerySet []>, limit = 21, num = 0

    def get(self, *args, **kwargs):
        """
        Perform the query and return a single object matching the given
        keyword arguments.
        """
        if self.query.combinator and (args or kwargs):
            raise NotSupportedError(
                "Calling QuerySet.get(...) with filters after %s() is not "
                "supported." % self.query.combinator
            )
        clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
        if self.query.can_filter() and not self.query.distinct_fields:
            clone = clone.order_by()
        limit = None
        if (
            not clone.query.select_for_update
            or connections[clone.db].features.supports_select_for_update_with_limit
        ):
            limit = MAX_GET_RESULTS
            clone.query.set_limits(high=limit)
        num = len(clone)
        if num == 1:
            return clone._result_cache[0]
        if not num:
>           raise self.model.DoesNotExist(
                "%s matching query does not exist." % self.model._meta.object_name
            )
E           stats.models.Daily.DoesNotExist: Daily matching query does not exist.

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:649: DoesNotExist

During handling of the above exception, another exception occurred:

self = <stats.tests.TestStats testMethod=test_posts_from_yesterday_are_updated>

    def test_posts_from_yesterday_are_updated(self):
        today = timezone.now()
        yesterday = today - dt.timedelta(days=1)
    
        yesterday_stats = Daily.objects.create(
            date=yesterday.date(),
            total_accounts=2,
            python_accounts=1,
            javascript_accounts=0,
            rust_accounts=0,
            ruby_accounts=0,
            golang_accounts=0,
            java_accounts=0,
            kotlin_accounts=0,
            scala_accounts=0,
            swift_accounts=0,
            csharp_accounts=0,
            fsharp_accounts=0,
            dotnet_accounts=0,
            cpp_accounts=0,
            linux_accounts=0,
            haskell_accounts=0,
            ocaml_accounts=0,
            nix_accounts=0,
            opensource_accounts=0,
            php_accounts=0,
        )
        account = Account.objects.create(
            account_id="2",
            instance="fosstodon.org",
            username="fosstest",
            acct="fosstest",
            display_name="Test Foss",
            locked=False,
            bot=False,
            discoverable=True,
            group=False,
            created_at="2021-01-01T00:00:00.000000+00:00",
            last_status_at="2021-01-01T00:00:00.000000+00:00",
            last_sync_at="2021-01-01T00:00:00.000000+00:00",
            followers_count=0,
            following_count=0,
            statuses_count=0,
            note="",
            url="https://fosstodon.org/@fosstest",
            avatar="https://fosstodon.org/@fosstest/avatar",
            avatar_static="https://fosstodon.org/@fosstest/avatar",
            header="https://fosstodon.org/@fosstest/header",
            header_static="https://fosstodon.org/@fosstest/header",
            emojis=[],
            roles=[],
            fields=[],
        )
        AccountLookup.objects.create(account=account, language="python")
        Post.objects.create(
            account=account,
            post_id="0",
            url="https://fosstodon.org/@fosstest/1",
            created_at=yesterday.isoformat(),
            content="Hello, world!",
            reblog=False,
            sensitive=False,
            spoiler_text="",
            visibility="public",
            language="python",
            emojis=[],
            replies_count=0,
            reblogs_count=0,
            favourites_count=0,
            mentions=[],
            tags=[],
        )
        Post.objects.create(
            account=account,
            post_id="1",
            url="https://fosstodon.org/@fosstest/1",
            created_at=today.isoformat(),
            content="Hello, world!",
            reblog=False,
            sensitive=False,
            spoiler_text="",
            visibility="public",
            language="python",
            replies_count=0,
            reblogs_count=0,
            favourites_count=0,
            emojis=[],
            mentions=[],
            tags=[],
        )
>       store_daily_stats()

stats/tests.py:152: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stats/models.py:25: in store_daily_stats
    Daily.objects.update_or_create(date=today, defaults=account_defaults | post_defaults)
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/manager.py:87: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:986: in update_or_create
    obj, created = self.select_for_update().get_or_create(
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:950: in get_or_create
    params = self._extract_model_params(defaults, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet []>
defaults = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}
params = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
property_names = frozenset({'pk'})
invalid_params = ['rstats_accounts', 'rstats_posts'], param = 'total_posts'

    def _extract_model_params(self, defaults, **kwargs):
        """
        Prepare `params` for creating a model instance based on the given
        kwargs; for use by get_or_create().
        """
        defaults = defaults or {}
        params = {k: v for k, v in kwargs.items() if LOOKUP_SEP not in k}
        params.update(defaults)
        property_names = self.model._meta._property_names
        invalid_params = []
        for param in params:
            try:
                self.model._meta.get_field(param)
            except exceptions.FieldDoesNotExist:
                # It's okay to use a model's property if it has a setter.
                if not (param in property_names and getattr(self.model, param).fset):
                    invalid_params.append(param)
        if invalid_params:
>           raise exceptions.FieldError(
                "Invalid field name(s) for model %s: '%s'."
                % (
                    self.model._meta.object_name,
                    "', '".join(sorted(invalid_params)),
                )
            )
E           django.core.exceptions.FieldError: Invalid field name(s) for model Daily: 'rstats_accounts', 'rstats_posts'.

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:1039: FieldError
self = <QuerySet []>
defaults = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}

    def get_or_create(self, defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, creating one if necessary.
        Return a tuple of (object, created), where created is a boolean
        specifying whether an object was created.
        """
        # The get() needs to be targeted at the write database in order
        # to avoid potential transaction consistency problems.
        self._for_write = True
        try:
>           return self.get(**kwargs), False

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:948: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet []>, args = ()
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}
clone = <QuerySet []>, limit = 21, num = 0

    def get(self, *args, **kwargs):
        """
        Perform the query and return a single object matching the given
        keyword arguments.
        """
        if self.query.combinator and (args or kwargs):
            raise NotSupportedError(
                "Calling QuerySet.get(...) with filters after %s() is not "
                "supported." % self.query.combinator
            )
        clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
        if self.query.can_filter() and not self.query.distinct_fields:
            clone = clone.order_by()
        limit = None
        if (
            not clone.query.select_for_update
            or connections[clone.db].features.supports_select_for_update_with_limit
        ):
            limit = MAX_GET_RESULTS
            clone.query.set_limits(high=limit)
        num = len(clone)
        if num == 1:
            return clone._result_cache[0]
        if not num:
>           raise self.model.DoesNotExist(
                "%s matching query does not exist." % self.model._meta.object_name
            )
E           stats.models.Daily.DoesNotExist: Daily matching query does not exist.

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:649: DoesNotExist

During handling of the above exception, another exception occurred:

self = <stats.tests.TestStats testMethod=test_store_daily_stats>

    def test_store_daily_stats(self):
>       store_daily_stats()

stats/tests.py:21: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stats/models.py:25: in store_daily_stats
    Daily.objects.update_or_create(date=today, defaults=account_defaults | post_defaults)
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/manager.py:87: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:986: in update_or_create
    obj, created = self.select_for_update().get_or_create(
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:950: in get_or_create
    params = self._extract_model_params(defaults, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet []>
defaults = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}
params = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
property_names = frozenset({'pk'})
invalid_params = ['rstats_accounts', 'rstats_posts'], param = 'total_posts'

    def _extract_model_params(self, defaults, **kwargs):
        """
        Prepare `params` for creating a model instance based on the given
        kwargs; for use by get_or_create().
        """
        defaults = defaults or {}
        params = {k: v for k, v in kwargs.items() if LOOKUP_SEP not in k}
        params.update(defaults)
        property_names = self.model._meta._property_names
        invalid_params = []
        for param in params:
            try:
                self.model._meta.get_field(param)
            except exceptions.FieldDoesNotExist:
                # It's okay to use a model's property if it has a setter.
                if not (param in property_names and getattr(self.model, param).fset):
                    invalid_params.append(param)
        if invalid_params:
>           raise exceptions.FieldError(
                "Invalid field name(s) for model %s: '%s'."
                % (
                    self.model._meta.object_name,
                    "', '".join(sorted(invalid_params)),
                )
            )
E           django.core.exceptions.FieldError: Invalid field name(s) for model Daily: 'rstats_accounts', 'rstats_posts'.

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:1039: FieldError
self = <QuerySet []>
defaults = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}

    def get_or_create(self, defaults=None, **kwargs):
        """
        Look up an object with the given kwargs, creating one if necessary.
        Return a tuple of (object, created), where created is a boolean
        specifying whether an object was created.
        """
        # The get() needs to be targeted at the write database in order
        # to avoid potential transaction consistency problems.
        self._for_write = True
        try:
>           return self.get(**kwargs), False

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:948: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet []>, args = ()
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}
clone = <QuerySet []>, limit = 21, num = 0

    def get(self, *args, **kwargs):
        """
        Perform the query and return a single object matching the given
        keyword arguments.
        """
        if self.query.combinator and (args or kwargs):
            raise NotSupportedError(
                "Calling QuerySet.get(...) with filters after %s() is not "
                "supported." % self.query.combinator
            )
        clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
        if self.query.can_filter() and not self.query.distinct_fields:
            clone = clone.order_by()
        limit = None
        if (
            not clone.query.select_for_update
            or connections[clone.db].features.supports_select_for_update_with_limit
        ):
            limit = MAX_GET_RESULTS
            clone.query.set_limits(high=limit)
        num = len(clone)
        if num == 1:
            return clone._result_cache[0]
        if not num:
>           raise self.model.DoesNotExist(
                "%s matching query does not exist." % self.model._meta.object_name
            )
E           stats.models.Daily.DoesNotExist: Daily matching query does not exist.

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:649: DoesNotExist

During handling of the above exception, another exception occurred:

self = <stats.tests.TestStats testMethod=test_store_daily_stats_with_accounts>

    def test_store_daily_stats_with_accounts(self):
        account = Account.objects.create(
            account_id="2",
            instance="fosstodon.org",
            username="fosstest",
            acct="fosstest",
            display_name="Test Foss",
            locked=False,
            bot=False,
            discoverable=True,
            group=False,
            created_at="2021-01-01T00:00:00.000000+00:00",
            last_status_at="2021-01-01T00:00:00.000000+00:00",
            last_sync_at="2021-01-01T00:00:00.000000+00:00",
            followers_count=0,
            following_count=0,
            statuses_count=0,
            note="",
            url="https://fosstodon.org/@fosstest",
            avatar="https://fosstodon.org/@fosstest/avatar",
            avatar_static="https://fosstodon.org/@fosstest/avatar",
            header="https://fosstodon.org/@fosstest/header",
            header_static="https://fosstodon.org/@fosstest/header",
            emojis=[],
            roles=[],
            fields=[],
        )
        AccountLookup.objects.create(account=account, language="python")
    
>       store_daily_stats()

stats/tests.py:56: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
stats/models.py:25: in store_daily_stats
    Daily.objects.update_or_create(date=today, defaults=account_defaults | post_defaults)
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/manager.py:87: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:986: in update_or_create
    obj, created = self.select_for_update().get_or_create(
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:950: in get_or_create
    params = self._extract_model_params(defaults, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <QuerySet []>
defaults = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
kwargs = {'date': datetime.datetime(2024, 5, 18, 0, 0, tzinfo=datetime.timezone.utc)}
params = {'angular_accounts': 0, 'angular_posts': 0, 'bootstrap_accounts': 0, 'bootstrap_posts': 0, ...}
property_names = frozenset({'pk'})
invalid_params = ['rstats_accounts', 'rstats_posts'], param = 'total_posts'

    def _extract_model_params(self, defaults, **kwargs):
        """
        Prepare `params` for creating a model instance based on the given
        kwargs; for use by get_or_create().
        """
        defaults = defaults or {}
        params = {k: v for k, v in kwargs.items() if LOOKUP_SEP not in k}
        params.update(defaults)
        property_names = self.model._meta._property_names
        invalid_params = []
        for param in params:
            try:
                self.model._meta.get_field(param)
            except exceptions.FieldDoesNotExist:
                # It's okay to use a model's property if it has a setter.
                if not (param in property_names and getattr(self.model, param).fset):
                    invalid_params.append(param)
        if invalid_params:
>           raise exceptions.FieldError(
                "Invalid field name(s) for model %s: '%s'."
                % (
                    self.model._meta.object_name,
                    "', '".join(sorted(invalid_params)),
                )
            )
E           django.core.exceptions.FieldError: Invalid field name(s) for model Daily: 'rstats_accounts', 'rstats_posts'.

/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/django/db/models/query.py:1039: FieldError