Source code for shoop.core.pricing._context

# This file is part of Shoop.
#
# Copyright (c) 2012-2015, Shoop Ltd. All rights reserved.
#
# This source code is licensed under the AGPLv3 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals

import abc
import hashlib

import six
from django.http import HttpRequest
from django.utils.encoding import force_bytes
from django.utils.timezone import now


class PricingContextable(six.with_metaclass(abc.ABCMeta)):
    """
    Object that is or can be converted to a pricing context.

    Currently there exists two kind of `PricingContextable` objects:
    `PricingContext`(and its subclasses) and `HttpRequest`.

    .. note::

       Expression ``isinstance(request, PricingContextable)`` will
       return True for a ``request`` which is `HttpRequest`, because
       `HttpRequest` is registered as a subclass of this abstract base
       class.

    This abstract base class is just a helper to allow writing simpler
    type specifiers, since we want to allow passing `HttpRequest` as a
    pricing context even though it is not a `PricingContext`.
    """
    pass
PricingContextable.register(HttpRequest)


class PricingContext(PricingContextable):
    """
    Context for pricing.
    """
    REQUIRED_VALUES = ()

    def __init__(self, **kwargs):
        kwargs.setdefault("time", now())
        for name, value in kwargs.items():
            setattr(self, name, value)
        for name in self.REQUIRED_VALUES:
            if not hasattr(self, name):
                raise ValueError("%s is a required value for %s but is not set." % (name, self))

[docs] def get_cache_key_parts(self): return [getattr(self, key) for key in self.REQUIRED_VALUES]
[docs] def get_cache_key(self): parts_text = "\n".join(force_bytes(part) for part in self.get_cache_key_parts()) return "%s_%s" % ( self.__class__.__name__, hashlib.sha1(parts_text).hexdigest() )
cache_key = property(get_cache_key)