Skip to main content

A decorator which prefers a precalculated attribute over calling the decorated method.

Project description

https://img.shields.io/pypi/v/fallback-property.svg Build Status https://coveralls.io/repos/github/jonasundderwolf/fallback-property/badge.svg?branch=master https://img.shields.io/pypi/pyversions/fallback-property.svg

Requirements

  • Python 3.6+

What is it?

fallback_property transforms a function into a property and uses the decorated function as fallback if no value was assigned to the property itself. A special descriptor (fallback_property.FallbackDescriptor) is used internally.

Django (or similar frameworks)

fallback_property is useful if you have a function that aggregates values from related objects, which could already be fetched using an annotated queryset. The decorator will favor the precalculated value over calling the actual method.

It is especially helpful, if you optimize your application and want to replace legacy or performance critical properties with precalulated values using .annotate().

How to use it?

Simply define a function and use the decorator fallback_property

from fallback_property import fallback_property

class Foo:

    @fallback_property()
    def fallback_func(self):
        return 7

Arguments

The fallback_property() has two optional arguments.

cached: bool = True

If the property is accessed multiple times, call the fallback function only once.

logging: bool = False

Log a warning if there was a fallback to the decorated, original method.

Usage Example (Django)

Suppose we have the following models

from django.db import models


class Pipeline(model.Model):
    @property
    def total_length(self):
        return sum(self.parts.values_list('length', flat=True))


class Parts(models.Model):
    length = models.PositiveIntegerField()
    pipeline = models.ForeignKey(Pipeline, related_name='parts')

Calling pipline.total_length will always trigger another query and is even more expensive when dealing with multiple objects. This can be optimized by using .annotate() and fallback_property()

from django.db import models, QuerySet
from django.db.functions import Coalesce
from django.db.models import Sum
from fallback_property import fallback_property


class PipelineQuerySet(QuerySet):

    def with_total_length(self):
        return self.annotate(
            total_length=Coalesce(
                Sum('parts__length', output_field=models.IntegerField()),
                0,
            )
        )


class Pipeline(model.Model):

    @fallback_property(logging=True)
    def total_length(self):
        return sum(self.parts.values_list('length', flat=True))

You can now access the total_length without triggering another query or get a warning, when the fallback function is used

pipeline = Pipeline.objects.with_total_length().first()
print(pipeline.total_length)

Important: The annotated value and the property must have the same name.

Development

This project is using poetry to manage all dev dependencies.

Clone this repository and run

poetry install
poetry run pip install django

to create a virtual environment with all dependencies.

You can now run the test suite using

poetry run pytest

This repository follows the angular commit conventions. You can register a pre-commit hook to validate your commit messages by using husky. The configurations are already in place if you have nodejs installed. Just run

npm install

and the pre-commit hook will be registered.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fallback-property-0.2.0.tar.gz (6.0 kB view details)

Uploaded Source

Built Distribution

fallback_property-0.2.0-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

Details for the file fallback-property-0.2.0.tar.gz.

File metadata

  • Download URL: fallback-property-0.2.0.tar.gz
  • Upload date:
  • Size: 6.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.45.0 CPython/3.8.2

File hashes

Hashes for fallback-property-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d38ade19054561af1ff1a75d31039f5433dc69a6f0dab575f4325f6cf3309a9e
MD5 c7720246d53735c7d191e90c47cf7045
BLAKE2b-256 ac6869bf9263c237af25f1c9a72a6f81e5faee98190820d96f5d3149b724f328

See more details on using hashes here.

File details

Details for the file fallback_property-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fallback_property-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 5.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/41.2.0 requests-toolbelt/0.9.1 tqdm/4.45.0 CPython/3.8.2

File hashes

Hashes for fallback_property-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 81df40929c17b1d5520e1a168cf28c926240a17f51455a7144d78d4689bfe786
MD5 0bfbd3214d4fe3b644b4cf7ed877ce0a
BLAKE2b-256 bb862df9de9c7c44472c1afa9d47638e1da14cdbd1e018c7f9c27f614bd8c72d

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page