Django Auxilium

Contents

Highlights

As mentioned in README, this library is a collection of various utilities for working in Django. This document highlights some of the most useful features. To see all of them you can either browse the source code or browse the API docs.

Models

Base models are available with common attributes:

Model fields

Useful fields:

  • RandomFileField - file field which always generates unique filename when storing new files
  • OriginalFilenameRandomFileField - file field which always generates unique filename when storing new files however stores original filename on specified field
  • RandomImageField - image field which always generates unique filename when storing new files
  • OriginalFilenameRandomImageField - image field which always generates unique filename when storing new files however stores original filename on specified field

Form fields

  • TypedFileField - file field which enforces allowed file extensions and/or mimetypes
  • MultipleValuesCharField - character field which normalizes to multiple values via any delimiter including regex. Useful when in UI multiple inputs cannot be used but multiple values need to be collected.

Signals

Model signal utility decorators:

  • file_field_auto_delete - this decorator automatically attaches appropriate signal to remove file fields when model is removed:

    >>> @file_field_auto_delete
    ... class FooModel(models.Model):
    ...     file = models.FileField(upload_to='foo')
    
  • file_field_auto_change_delete - this decorator automatically attaches appropriate signal to remove file fields when model is removed:

    >>> from dirtyfields import DirtyFieldsMixin
    >>> @file_field_auto_change_delete
    ... class FooModel(DirtyFieldsMixin, models.Model):
    ...     file = models.FileField(upload_to='foo')
    
  • auto_signals - this decorator allows to define model signals within the model which are returned as part of get_signals() method:

    >>> @auto_signals
    ... class MyModel(models.Model):
    ...     @classmethod
    ...     def get_signals(cls):
    ...         def so_something_pre_save(sender, instance, *args, **kwargs):
    ...             print('doing something on pre_save')
    ...         return [
    ...             {
    ...                 'receiver': so_something,
    ...                 'weak': False,
    ...                 'dispatch_uid': 'my_signal_uuid',
    ...             },
    ...         ]
    

Middleware

Decorators

Utilities
  • cache - decorator for caching either stand-alone functions or class methods so that they are only executed once. Useful for expensive functions which do not accept any parameters:

    >>> @cache
    def my_expensive_function():
    ...     return list(zip(range(1000000), range(1000000)))
    
  • memoize - decorator for caching either stand-alone functions or class methods which cache results per given parameters so that subsequent calls with same parameters are not executed. Useful for expensive functions which accept parameters:

    >>> @memoize
    ... def fib(n):
    ...     if n == 0:
    ...         return 0
    ...     elif n == 1:
    ...         return 1
    ...     else:
    ...         return fib(n - 1) + fib(n - 2)
    
  • lazy - decorator for making functions execute lazily. They only execute once any operation is executed on their result, including type checking:

    >>> @lazy(str)
    ... def foo(self):
    ...     print('executing foo')
    ...     return foo
    
    >>> f = foo()
    >>> isinstance(f, str)
    executing foo
    True
    >>> f == 'foo'
    True
    
Bases

These base decorator classes are available which can be used to create class-based-decorators. They aim to provide to decorators what Django did with class-based-views to regular views. Both have a place however for more complex tasks separating logic within decorator might be more useful. As a matter of fact, the above decorators are all implemented on top of these base classes:

  • Decorator - this is a base class for creating class-based-decorators:

    >>> class MyPartialDecorator(Decorator):
    ...     def __init__(self, *args, **kwargs):
    ...         self.args = args
    ...         self.kwargs = kwargs
    ...     def get_wrapped_object(self):
    ...         def wrapper(*args, **kwargs):
    ...             _args = self.args + args
    ...             _kwargs = self.kwargs.copy()
    ...             _kwargs.update(kwargs)
    ...             return self.to_wrap(*_args, **_kwargs)
    ...         return wrapper
    
    >>> my_partial = MyPartialDecorator.as_decorator()
    
  • HybridDecorator - this is a base class for creating class-based-decorators which can wrap both standalone functions and class methods:

    >>> class MyDecorator(Decorator):
    ...     def get_wrapped_object(self):
    ...         if self.in_class:
    ...             # class method
    ...         else:
    ...             # standalone function
    
    >>> my_decorator = MyDecorator.as_decorator()
    

History

0.1.4 (2018-05-26)

  • Added: New APi for setting cache values. Now can do Class.method.push(value, *args, **kwargs).

0.1.3 (2018-05-24)

  • Fixed: Django 2.0 support for minify middleware.

0.1.2 (2017-11-22)

  • Fixed: Not removing all spaces between html tags. Sometimes spaces matter for formatting. For example <strong>Hello</strong> <i>World</i> cannot be minified any further.

0.1.1 (2016-09-26)

  • Fixed: Cache properties now allow to set cache value via foo = bar syntax when cache descriptor has as_property == True

0.1.0 (2015-11-26)

  • First release on PyPI.

django_auxilium

django_auxilium package

Subpackages
django_auxilium.callback_mail package

This package provides provides custom email backends which use Django signals framework to send signals when various mail sending progress events occur.

You can refer to signals for a full list of supported signals.

In order to enable this functionality, you need to change your Django email backend:

EMAIL_BACKEND = 'django_auxilium.callback_mail.filebased.EmailBackend'

Examples

from django.dispatch import receiver
from django_auxilium.callback_mail.signals import sent_mail

@receiver(sent_mail)
def my_callback(sender, message):
    print("Message sent!")
Submodules
django_auxilium.callback_mail.base module
class django_auxilium.callback_mail.base.BaseCallbackEmailBackendMixin[source]

Bases: object

Base class for implementing callback email backends.

“Callback” is used in a sense that appropriate signals are sent while sending message.

Sending:signals.sending_mail signal is sent when message is in progress of being sent
Sent:signals.sent_mail signal is sent when message was successfully sent
Failed:signals.failed_mail signal is sent when message sending failed
failed(message, reason=None)[source]

Hook which sends signal when sending message failed

sending(message)[source]

Hook which sends signal when message is being sent

sent(message)[source]

Hook which sends signal when message was successfully sent

django_auxilium.callback_mail.filebased module
class django_auxilium.callback_mail.filebased.CallbackEmailBackend(*args, **kwargs)[source]

Bases: django_auxilium.callback_mail.base.BaseCallbackEmailBackendMixin, django.core.mail.backends.filebased.EmailBackend

Custom file-based email backend which sends signals on progress events of sending messages.

send_messages(email_messages)[source]

Custom implementation of sending messages which also calls mail signals.

Unfortunately vanilla Django implementation does not provide enough hooks for when messages are sent hence this method needs to duplicate the whole method.

django_auxilium.callback_mail.signals module
django_auxilium.callback_mail.signals.failed_mail = <django.dispatch.dispatcher.Signal object>

Signal sent when message sending has failed

Parameters:
  • message – Email message which was not sent
  • reason (str) – Reason for why message was not sent
django_auxilium.callback_mail.signals.sending_mail = <django.dispatch.dispatcher.Signal object>

Signal sent when message is being sent.

Parameters:message – Email message which is being sent
django_auxilium.callback_mail.signals.sent_mail = <django.dispatch.dispatcher.Signal object>

Signal sent when message has successfully been sent

Parameters:message – Email message which was sent
django_auxilium.callback_mail.smtp module
class django_auxilium.callback_mail.smtp.CallbackEmailBackend(host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, ssl_keyfile=None, ssl_certfile=None, **kwargs)[source]

Bases: django_auxilium.callback_mail.base.BaseCallbackEmailBackendMixin, django.core.mail.backends.smtp.EmailBackend

Custom SMPT email backend which sends signals on progress events of sending messages.

send_messages(email_messages)[source]

Custom implementation of sending messages which also calls mail signals.

Unfortunately vanilla Django implementation does not provide enough hooks for when messages are sent hence this method needs to duplicate the whole method.

django_auxilium.forms package
Submodules
django_auxilium.forms.color module
class django_auxilium.forms.color.ColorCharField(*args, **kwargs)[source]

Bases: django.forms.fields.CharField

Custom django field which is able to validate colors as input.

Parameters:type (str) –

The type of the color format. The supported formats are

hex:

The hexadecimal notation of the color. Examples is:

ff0000
#00ff00

This type also allows to specify these additional parameters:

hash_required : bool

If the # is required in the value (e.g. '#ff0000')

hash_output : bool

If the # is required in the output validated value in to_python

Raises:ValueError – If unsupported type color type is provided
default_error_messages = {u'invalid': u'Invalid color value.'}
to_python(value)[source]

Convert to a validated string color value.

django_auxilium.forms.files module
class django_auxilium.forms.files.TypedFileField(*args, **kwargs)[source]

Bases: django.forms.fields.FileField

Typed FileField which allows to make sure the uploaded file has the appropriate type.

File type can be verified either by extension and/or mimetype.

This field accepts all the parameters as FileField, however in addition it accepts some additional parameters as documented below.

Examples

TypedFileField(ext_whitelist=['jpg', 'jpeg'],
               type_whitelist=['image/jpeg'])

Warning

If use_magic is used, please make sure that python-magic is installed. This library does not require it by default.

Parameters:
  • ext_whitelist (list, optional) – List of allowed file extensions. Note that each extension should emit the first period. For example for filename 'example.jpg', the allowed extension should be 'jpg'.
  • type_whitelist (list, optional) – List of allowed file mimetypes.
  • use_magic (bool, optional) – If type_whitelist is specified, this boolean determines whether to use python-magic (based of top of libmagic) to determine the mimetypes of files instead of relying on Django’s UploadedFile.content_type. Django does not take any real care to determine any accurately the mimetype so it is recommended to leave this parameter as True which is the default value.
default_error_messages = {u'extension': u'File extension is not supported.', u'mimetype': u'File mimetype is not supported.'}
validate(value)[source]

Validate that the file is of supported extension and/or type.

django_auxilium.forms.multiple_values module
class django_auxilium.forms.multiple_values.MultipleValuesCharField(delimiter=u', ', separator=u', ', mapping=None, max_values=None, min_values=None, strip=True, disregard_empty=True, invalid_values=None, *args, **kwargs)[source]

Bases: django.forms.fields.CharField

Form field to allow users to enter multiple values.

The best approach to enter multiple values is to provide a user with multiple input fields however sometimes that is not feasible. In that case this field provides a way for a user to enter multiple values in a single input field. The values can be delimited by either a constant character(s) or even by a regular expression.

Examples

MultipleValuesCharField(delimiter=',')
MultipleValuesCharField(delimiter=',', min_values=1, max_values=10)
MultipleValuesCharField(delimiter=re.compile(r'\W+'), separator='\n')
MultipleValuesCharField(mapping=int)
MultipleValuesCharField(mapping=lambda i: i == 5)
MultipleValuesCharField(mapping={'foo': 'bar'})
Parameters:
  • delimiter (str, Regex, optional) – The delimiter according to which the values are split. It can also be given as a compiled regular expression (e.g. re.compile('\W+')). Default is ',' (comma).
  • separator (str) – Iff the delimiter is a regular expression, then this value will be used to separate values within the widget when rendering values back in the UI.
  • mapping (dict, callable, optional) – By default all split values are casted to a Python string. The mapping allows to change that so that individual values will be mapped to different data-types. Mapping can be defined as a callable which will should accept one parameter, the value, and return the input value properly casted. Mapping can also be defined as a dictionary. In that case, if the individual value exists as a key of the dictionary, the value associated with the key will be used as a final casted value. Please note that if the key is not found in the dictionary, then the input value will be used. Default is None.
  • max_values (int, optional) – The maximum allowed number of values. Default is None.
  • min_values (int, optional) – The minimum required number of provided values. Default is None.
  • strip (bool, optional) – If True, then once the user string is split, all values are stripped of whitespace on either side of the string before being converted to Python value by using Python’s string strip(). Default is True.
  • disregard_empty (bool, optional) – If True, then once input string is split, all false evaluated values are disregarded. Default is True.
  • invalid_values (list, optional) – If provided, this list determines which values are invalid and if any are encountered, a ValidationError will be raised. Useful to blacklist specific values for being validated. If more complex logic is required, please consider using mapping as a callable function.
default_error_messages = {u'invalid_value': u'{0} is an invalid value.', u'invalid_values': u'{0} are invalid values.', u'max_values': u'Ensure this value has at least {0} values (it has {1}).', u'min_values': u'Ensure this value has at most {0} values (it has {1}).'}
prepare_value(values)[source]

Prepare values to be displayed in the UI.

By default this method joins all the values by the separator if the values is a list or tuple. Otherwise, this method returns the value itself. Having this method does not require to define a custom widget for this form field.

run_validators(values)[source]

Run regular Django field validators for each of the values.

to_python(value)[source]

Convert the input value to a list of values.

Also does basic validation via the mapping especially when it is a callable and so can raise exceptions.

Returns:
Return type:list
validate(values)[source]

Validate values

Primarily this method validates:

  • that min_values and max_values are honored
  • that invalid_values were not supplied
django_auxilium.forms.range module
class django_auxilium.forms.range.RangeSelectorField(*args, **kwargs)[source]

Bases: django.forms.fields.CharField

Range field which supports Excel-type rangeconfig selectors.

The rangeconfig selection is made using the following format:

<Column><Row>:<Column><Row>

Examples

A:A
A1:A50
1:50
Parameters:
  • max_rows (int, optional) – The maximum number of rows the range can have
  • max_columns (int, optional) – The maximum number of columns the range can have
  • max_either (int, optional) – The maximum number of rows and columns the range can have. For example if the value is 1 then either a single column or a single row can be selected.
  • required_rows (bool, optional) – Whether rows must be supplied in the rangeconfig
  • required_columns (bool, optional) – Whether columns must be supplied in the rangeconfig
default_error_messages = {u'invalid': u'Invalid range value.', u'max_columns': u'Too many columns selected. Maximum is {0}.', u'max_either': u'Too many rows or columns selected. Maximum is {0}.', u'max_rows': u'Too many rows selected. Maximum is {0}.', u'max_total': u'Too many total cells selected. Maximum is {0}.', u'required_columns': u'Column selection is required.', u'required_rows': u'Row selection is required.', u'values': u'Top-left coordinate must be first.'}
to_python(value)[source]

Convert range string value to Range rangeconfig value.

Returns:
Return type:Range
validate(value)[source]

Validate the rangeconfig value.

Following is validated:

  • rows or columns are supplied depending on required_row and required_columns parameters
  • rangeconfig is given as top-left to bottom-right
  • columns range is within max_columns
  • rows range is within max_rows
  • both columns and rows range is within max_either
django_auxilium.middleware package
Submodules
django_auxilium.middleware.html module
class django_auxilium.middleware.html.MinifyHTMLMiddleware(get_response=None)[source]

Bases: object

Middleware for minifying HTML.

Unlike some other minifyers, this minifyer is pretty simple and tried to do the bare minimum in an attempt of being super-lightweight.

This middleware only works when settings.DEBUG is disabled.

See also

django_auxilium.utils.html.simple_minify
What is used to actually minify HTML
process_response(request, response)[source]

Process the response by minifying HTML.

HTML is minified only when the response content type is HTML (e.g. contains 'text/html').

django_auxilium.models package
Subpackages
django_auxilium.models.fields package
Submodules
django_auxilium.models.fields.files module

Collection of Django custom model field which have something to do with files

class django_auxilium.models.fields.files.OriginalFilenameRandomFileField(*args, **kwargs)

Bases: django_auxilium.models.fields.files.RandomFileNameWithFilenameFileFieldMixin, django.db.models.fields.files.FileField

class django_auxilium.models.fields.files.OriginalFilenameRandomImageField(*args, **kwargs)

Bases: django_auxilium.models.fields.files.RandomFileNameWithFilenameFileFieldMixin, django.db.models.fields.files.ImageField

class django_auxilium.models.fields.files.RandomFileField(*args, **kwargs)

Bases: django_auxilium.models.fields.files.RandomFileNameFileFieldMixin, django.db.models.fields.files.FileField

class django_auxilium.models.fields.files.RandomFileFieldDeconstructMixin[source]

Bases: object

Mixin for random filename file mixins which implements Django’s deconstruct to be Django-migrations compatible

deconstruct()[source]

Standard Django’s deconstruct in order to enable migrations support

class django_auxilium.models.fields.files.RandomFileNameFileFieldMixin(*args, **kwargs)[source]

Bases: django_auxilium.models.fields.files.RandomFileFieldDeconstructMixin

Mixing for a custom FileField which generates random filename

Parameters:upload_to (str) – String where uploaded files should be saved. Within that directory, random filename will always be selected.
class django_auxilium.models.fields.files.RandomFileNameWithFilenameFileFieldMixin(*args, **kwargs)[source]

Bases: django_auxilium.models.fields.files.RandomFileFieldDeconstructMixin

Mixing for a custom FileField which generates random filename and also stores original filename

Parameters:
  • upload_to (str) – String where uploaded files should be saved. Within that directory, random filename will always be selected.
  • filename_field (str) – Name of Django model field name where original filename should be stored
class django_auxilium.models.fields.files.RandomImageField(*args, **kwargs)

Bases: django_auxilium.models.fields.files.RandomFileNameFileFieldMixin, django.db.models.fields.files.ImageField

django_auxilium.models.fields.files.original_random_filename_upload_to(path, filename_field)[source]

Get upload_to compliant method which will always return a random filename however will also store the original filename in the model.

Parameters:
  • path (str) – The path relative to media where the filaname should be uploaded to
  • filename_field (str) – The name of the model attribute to which the original filename should be stored.
Returns:

upload_to – Django FileField’s upload_to compliant function

Return type:

function

django_auxilium.models.fields.files.random_filename_upload_to(path)[source]

Get upload_to compliant method which will always return a random filename.

This method can be used as Django’s FileField upload_to parameter. It returns an upload_to callable which will make sure the filename will always be random. This method also accepts a path parameter which will define where relative to the media folder, the file will be stored.

Parameters:path (str) – The path relative to media where the filename should be uploaded to
Returns:upload_to – Django FileField’s upload_to compliant function
Return type:function
Submodules
django_auxilium.models.base module

Collection of simple abstract base models with a few additional attributes which don’t require much logic.

class django_auxilium.models.base.BaseModel(*args, **kwargs)[source]

Bases: django_auxilium.models.base.CreatedModel, django_auxilium.models.base.ModifiedModel

This model adds date created and last date modified attributes

class Meta[source]

Bases: object

abstract = False
get_next_by_created(**morekwargs)
get_next_by_modified(**morekwargs)
get_previous_by_created(**morekwargs)
get_previous_by_modified(**morekwargs)
class django_auxilium.models.base.CreatedModel(*args, **kwargs)[source]

Bases: django.db.models.base.Model

This model adds date created attribute

created

DateTimeField – The datetime when the model instance is created

class Meta[source]

Bases: object

abstract = False
created

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_created(**morekwargs)
get_previous_by_created(**morekwargs)
class django_auxilium.models.base.ModifiedModel(*args, **kwargs)[source]

Bases: django.db.models.base.Model

This model adds the last date modified attribute

modified

DateTimeField – The datetime when the model was last modified and saved

class Meta[source]

Bases: object

abstract = False
get_next_by_modified(**morekwargs)
get_previous_by_modified(**morekwargs)
modified

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class django_auxilium.models.base.NoteModel(*args, **kwargs)[source]

Bases: django_auxilium.models.base.BaseModel

This model adds a notes field

notes

TextField – Text field for storing notes

class Meta[source]
abstract = False
get_next_by_created(**morekwargs)
get_next_by_modified(**morekwargs)
get_previous_by_created(**morekwargs)
get_previous_by_modified(**morekwargs)
notes

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class django_auxilium.models.base.TitleDescriptionModel(*args, **kwargs)[source]

Bases: django_auxilium.models.base.BaseModel

This model adds a title and description fields

title

CharField – Maximum length is 256 character

description

TextField

class Meta[source]
abstract = False
description

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_next_by_created(**morekwargs)
get_next_by_modified(**morekwargs)
get_previous_by_created(**morekwargs)
get_previous_by_modified(**morekwargs)
title

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class django_auxilium.models.base.UserModel(*args, **kwargs)[source]

Bases: django.db.models.base.Model

This model adds a foreign key to a user attribute

user

User – The user associated with the model

class Meta[source]

Bases: object

abstract = False
user

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

child.parent is a ForwardManyToOneDescriptor instance.

user_id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

django_auxilium.models.signals module
class django_auxilium.models.signals.AutoSignals(getter=u'get_signals', signal_pool=None)[source]

Bases: django_auxilium.utils.functools.decorators.Decorator

Decorator for automatically attaching signals to the model class.

Usual Django convention is to include all signals in signals.py. That works really well in most cases however here are potential disadvantages:

  • it couples logic to a model class in different Python module
  • signals need to be imported somewhere in app initialization process

These issues can be resolved by moving the signal receivers to models.py however some issues with that are:

  • signals need to be defined after model definitions
  • if there are many models, it could be hard to find associated signals

This decorator attempts to solve that by moving the signal receiver definitions to the model itself which are retrieved via class method get_signals. It allows to tightly couple model signal receivers within the model which in some cases might be better compared to using signals.py module.

get_signals expected to return a list of signals which should be attached to the model class. That could either be achieved by returning either receiver handler callables or signal dict parameters. Here is a description of what each of them can do:

Callables:

An example:

>>> import random
>>> @auto_signals
... class MyModel(models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     @staticmethod
...     def do_pre_save(sender, instance, *args, **kwargs):
...         print('triggered pre_save')
...     @staticmethod
...     def do_post_save(sender, instance, *args, **kwargs):
...         print('triggered post_save')
...     @classmethod
...     def get_signals(cls):
...         return [cls.do_pre_save, cls.do_post_save]

When get_signals returns a list of signal receivers, each receiver function name should contain the signal name to which it needs to connect to. By default this decorator supports all Django model signals. If different signals need to be supported, please use signal_pool parameter.

Dictionary:

An example:

>>> import random
>>> @auto_signals
... class MyModel(models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     @classmethod
...     def get_signals(cls):
...         def so_something(sender, instance, *args, **kwargs):
...             print('doing something')
...         def do_something_else_post_save(sender, instance, *args, **kwargs):
...             print('doing something else')
...         return [
...             {
...                 'receiver': so_something,
...                 'weak': False,
...                 'dispatch_uid': 'my_signal_uuid',
...                 'signal': 'pre_save',
...             },
...             {
...                 'receiver': do_something_else_post_save,
...                 'weak': False,
...                 'dispatch_uid': 'my_other_signal_uuid',
...             },
...         ]

When get_signals returns a list of signal dictionaries, each dict should be parameters which will be passed to Django’s Signal.connect. The only exception is the optional signal key which when given should either be a name of the supported signal as per signal_pool or actual signal object. When not provided, this decorator will figure out the signal from the receiver’s name, same as when get_signals returns a list of callables as described above.

Parameters:
  • getter (str, optional) – Name of the class method on the decorated model which should return signals to be connected
  • signal_pool (dict, optional) – Dictionary of supported signals. Keys should be signal names and values should be actual signal objects. By default all model signals are supported.
connect_signal(signal)[source]

Connect individual signal to the decorated model

Parameters:signal (dict, function) – Either a dict or a function of the receiver signal handler. For more information about how each of those are handled, please AutoSignals description.
connect_signals()[source]

Connect all signals as returned by the signal getter on the decorated model

See also

connect_signal()

get_wrapped_object()[source]

Return the given model

Since signals are connected externally of a model class, the model class is not modified.

validate_model()[source]

Validate that the decorated object is a valid Django model class and that it implements signal getter.

class django_auxilium.models.signals.FieldSpec(name, field)

Bases: tuple

Field specification which is used by file descriptors to reference the field name and field object itself during decorator operations.

field

Alias for field number 1

name

Alias for field number 0

class django_auxilium.models.signals.FileFieldAutoChangeDelete(*args, **kwargs)[source]

Bases: django_auxilium.models.signals.FileFieldAutoDelete

Model decorator which automatically setups all the necessary signals to automatically remove files associated with given fields when they change on model save.

Unlike FileFieldAutoDelete which removed file fields on model deletion, this decorator removes files if they are changed. The premise is that if the file field is editable if it is changed either in Django Admin or in custom logic, unless custom logic is applied, by default Django would not remove the old file hence over time many orphan files can accumulate on the server. Locally it might not be a big deal however when external (especially paid) storage backend is used, extra files can make a real difference over time. This decorator automatically handles that and removes old files when they are changed.

In order to do that however model has to track when files change on the model and Django models do not do that out of the box. You can either implement that functionality yourself on the model by implementing the following methods:

  • is_dirty() - should return a bool if any of the model fields have changed. Usually this will require to track model fields during __init__ which will be used to initialize model instance when querying model from db and then comparing those values with the new values when this method is called.
  • get_dirty_fields() - should return a dict where the keys are the field names and the values are old field values.

Alternatively you can use a third-party package which implements that API. This decorator is tested with django-dirtyfields.

Warning

As mentioned above, this decorator requires is_dirty() and get_dirty_fields() to be implemented on the model. Even though we recommend to use django-dirtyfields for that functionality, this library does not ship with django-dirtyfields pre-installed and you will need to install it independently.

Note

This decorator does not remove files on delete as well. If you would like to both remove files on both delete and change you will need to apply both FileFieldAutoDelete and this decorator at the same time.

Examples

>>> import random
>>> from dirtyfields import DirtyFieldsMixin

>>> @file_field_auto_change_delete  # equivalent to @file_field_auto_change_delete('*')
... class FooModel(DirtyFieldsMixin, models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')

>>> @file_field_auto_change_delete('file')
... class FooModel(DirtyFieldsMixin, models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')

>>> # remote both on delete and change
>>> @file_field_auto_delete
... @file_field_auto_change_delete
... class FooModel(DirtyFieldsMixin, models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')
Parameters:
  • fields (str, list) – Same as FileFieldAutoDelete fields parameter
  • signal (Signal, optional) – Same as FileFieldAutoDelete signal parameter. By default is post_save signal.
  • signal_name_pattern (str, optional) – The name given to the signal function which will automatically remove the file. This can be a string formatted string. Into it, two parameters will be passed which are model and field. model is a model class (not instance) to which the signal is being connected to and field is a name of the file field (or '_' delimited field names if multiple fields are given). The default pattern is post_save_{model.__name__}_delete_{field} which results in patterns like 'post_save_Model_delete_file_field'. The reason why this pattern might be useful is because it can be used to disconnect the signal receiver at a later time.
get_signal_function()[source]

Get the actual function which will be connected to the Django’s signal which conforms to the post_save signal signature:

def receiver(sender, instance, *args, **kwargs): pass
validate_model()[source]

Validate that the model is a valid Django model and that it implements necessary API in order to track that model fields have changed before saving.

class django_auxilium.models.signals.FileFieldAutoDelete(fields=u'*', signal=None, signal_name_pattern=None)[source]

Bases: django_auxilium.utils.functools.decorators.Decorator

Model decorator which automatically setups all the necessary signals to automatically remove files associated with given fields when model instance is removed.

Starting with Django 1.3 when model records are deleted via querysets (e.g. model.objects.filter(...).delete()), the model’s delete() method is no longer called. As a consequence, if the model has any file fields, those files will not be removed even if it is specified in the delete() method. The new way to remove files associated with a model is to use Django signals framework, or more specifically the post_delete signal. This decorator automatically connects the post_delete signal which will remove the file associated with the specified file field.

More about this can be found at Django 1.3 release notes.

Examples

>>> import random
>>> @file_field_auto_delete  # equivalent to @file_field_auto_delete('*')
... class FooModel(models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')

>>> import random
>>> @file_field_auto_delete('file')
... class FooModel(models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')
Parameters:
  • fields (str, list) – Either a single file field which should be removed on delete or a list of fields. Also '*' can be used in order to delete all FileField on the model.
  • signal (Signal, optional) – Djagno signal class which should be used to attach the receiver signal handler to. By default is post_delete signal.
  • signal_name_pattern (str, optional) – The name given to the signal function which will automatically remove the file. This can be a string formatted string. Into it, two parameters will be passed which are model and field. model is a model class (not instance) to which the signal is being connected to and field is a name of the file field (or '_' delimited field names if multiple fields are given). The default pattern is post_delete_{model.__name__}_delete_{field} which results in patterns like 'post_delete_Model_delete_file_field'. The reason why this pattern might be useful is because it can be used to disconnect the signal receiver at a later time.
field_names

list – List of normalized field names which should be removed on change

fields

list – List of validated FieldSpec which signal will use to remove changed files

signal_name_pattern

str – Same as the signal_name_pattern parameter

connect_signal_function()[source]

Connect the signal as returned by get_signal_function() into the Django’s signal’s framework.

get_field_by_name(name)[source]

Get a Django model field for the given field name from the decorated model

Parameters:name (str) – Name of the field to get
Returns:Django model field instance
Return type:Field
get_field_names()[source]

Get list of field names to be removed in the created signal

This method is primarily used to normalize the list of fields in case it is provided as a string, list or a wildcard '*'.

Returns:List of field names which should be removed in the created signal
Return type:list
get_fields()[source]

Get list of FieldSpec for all the fields to be removed

get_signal_function()[source]

Get the actual function which will be connected to the Django’s signal which conforms to the post_delete signal signature:

def receiver(sender, instance, *args, **kwargs): pass
get_signal_name()[source]

Using the signal_name_pattern pattern, return the formatted signal name.

Returns:name – The name of the signal
Return type:str
get_wrapped_object()[source]

Return the given model

Since signals are connected externally of a model class, the model class is not modified.

validate_field(name)[source]

Validate a single field on the model

This method is expected to be called after validate_model() and it assumes that self.to_wrap is a valid Django model. It also validates that the given field name is present in the model and that it subclasses Django’s FileField field class.

Raises:
  • AttributeError – When the field cannot be found on the model
  • TypeError – When the field is not a FileField
validate_fields()[source]

Validate all the fields on the model

This method is expected to be called after validate_model() and it assumes that self.to_wrap is a valid Django model. This method validates that the given fields are present in the model and that they are a subclass of Django’s FileField field class.

See also

validate_field()

validate_model()[source]

Validate the input to the decorator which is suppose to be a model

Make sure the given class is a subclass of Django’s Model class.

Raises:TypeError – If to_wrap is either not a class or not a Django’s model.Model class.
django_auxilium.models.signals.auto_signals(*args, **kwargs)

Decorator for automatically attaching signals to the model class.

Usual Django convention is to include all signals in signals.py. That works really well in most cases however here are potential disadvantages:

  • it couples logic to a model class in different Python module
  • signals need to be imported somewhere in app initialization process

These issues can be resolved by moving the signal receivers to models.py however some issues with that are:

  • signals need to be defined after model definitions
  • if there are many models, it could be hard to find associated signals

This decorator attempts to solve that by moving the signal receiver definitions to the model itself which are retrieved via class method get_signals. It allows to tightly couple model signal receivers within the model which in some cases might be better compared to using signals.py module.

get_signals expected to return a list of signals which should be attached to the model class. That could either be achieved by returning either receiver handler callables or signal dict parameters. Here is a description of what each of them can do:

Callables:

An example:

>>> import random
>>> @auto_signals
... class MyModel(models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     @staticmethod
...     def do_pre_save(sender, instance, *args, **kwargs):
...         print('triggered pre_save')
...     @staticmethod
...     def do_post_save(sender, instance, *args, **kwargs):
...         print('triggered post_save')
...     @classmethod
...     def get_signals(cls):
...         return [cls.do_pre_save, cls.do_post_save]

When get_signals returns a list of signal receivers, each receiver function name should contain the signal name to which it needs to connect to. By default this decorator supports all Django model signals. If different signals need to be supported, please use signal_pool parameter.

Dictionary:

An example:

>>> import random
>>> @auto_signals
... class MyModel(models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     @classmethod
...     def get_signals(cls):
...         def so_something(sender, instance, *args, **kwargs):
...             print('doing something')
...         def do_something_else_post_save(sender, instance, *args, **kwargs):
...             print('doing something else')
...         return [
...             {
...                 'receiver': so_something,
...                 'weak': False,
...                 'dispatch_uid': 'my_signal_uuid',
...                 'signal': 'pre_save',
...             },
...             {
...                 'receiver': do_something_else_post_save,
...                 'weak': False,
...                 'dispatch_uid': 'my_other_signal_uuid',
...             },
...         ]

When get_signals returns a list of signal dictionaries, each dict should be parameters which will be passed to Django’s Signal.connect. The only exception is the optional signal key which when given should either be a name of the supported signal as per signal_pool or actual signal object. When not provided, this decorator will figure out the signal from the receiver’s name, same as when get_signals returns a list of callables as described above.

Parameters:
  • getter (str, optional) – Name of the class method on the decorated model which should return signals to be connected
  • signal_pool (dict, optional) – Dictionary of supported signals. Keys should be signal names and values should be actual signal objects. By default all model signals are supported.
django_auxilium.models.signals.file_field_auto_change_delete(*args, **kwargs)

Model decorator which automatically setups all the necessary signals to automatically remove files associated with given fields when they change on model save.

Unlike FileFieldAutoDelete which removed file fields on model deletion, this decorator removes files if they are changed. The premise is that if the file field is editable if it is changed either in Django Admin or in custom logic, unless custom logic is applied, by default Django would not remove the old file hence over time many orphan files can accumulate on the server. Locally it might not be a big deal however when external (especially paid) storage backend is used, extra files can make a real difference over time. This decorator automatically handles that and removes old files when they are changed.

In order to do that however model has to track when files change on the model and Django models do not do that out of the box. You can either implement that functionality yourself on the model by implementing the following methods:

  • is_dirty() - should return a bool if any of the model fields have changed. Usually this will require to track model fields during __init__ which will be used to initialize model instance when querying model from db and then comparing those values with the new values when this method is called.
  • get_dirty_fields() - should return a dict where the keys are the field names and the values are old field values.

Alternatively you can use a third-party package which implements that API. This decorator is tested with django-dirtyfields.

Warning

As mentioned above, this decorator requires is_dirty() and get_dirty_fields() to be implemented on the model. Even though we recommend to use django-dirtyfields for that functionality, this library does not ship with django-dirtyfields pre-installed and you will need to install it independently.

Note

This decorator does not remove files on delete as well. If you would like to both remove files on both delete and change you will need to apply both FileFieldAutoDelete and this decorator at the same time.

Examples

>>> import random
>>> from dirtyfields import DirtyFieldsMixin

>>> @file_field_auto_change_delete  # equivalent to @file_field_auto_change_delete('*')
... class FooModel(DirtyFieldsMixin, models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')

>>> @file_field_auto_change_delete('file')
... class FooModel(DirtyFieldsMixin, models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')

>>> # remote both on delete and change
>>> @file_field_auto_delete
... @file_field_auto_change_delete
... class FooModel(DirtyFieldsMixin, models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')
Parameters:
  • fields (str, list) – Same as FileFieldAutoDelete fields parameter
  • signal (Signal, optional) – Same as FileFieldAutoDelete signal parameter. By default is post_save signal.
  • signal_name_pattern (str, optional) – The name given to the signal function which will automatically remove the file. This can be a string formatted string. Into it, two parameters will be passed which are model and field. model is a model class (not instance) to which the signal is being connected to and field is a name of the file field (or '_' delimited field names if multiple fields are given). The default pattern is post_save_{model.__name__}_delete_{field} which results in patterns like 'post_save_Model_delete_file_field'. The reason why this pattern might be useful is because it can be used to disconnect the signal receiver at a later time.
django_auxilium.models.signals.file_field_auto_delete(*args, **kwargs)

Model decorator which automatically setups all the necessary signals to automatically remove files associated with given fields when model instance is removed.

Starting with Django 1.3 when model records are deleted via querysets (e.g. model.objects.filter(...).delete()), the model’s delete() method is no longer called. As a consequence, if the model has any file fields, those files will not be removed even if it is specified in the delete() method. The new way to remove files associated with a model is to use Django signals framework, or more specifically the post_delete signal. This decorator automatically connects the post_delete signal which will remove the file associated with the specified file field.

More about this can be found at Django 1.3 release notes.

Examples

>>> import random
>>> @file_field_auto_delete  # equivalent to @file_field_auto_delete('*')
... class FooModel(models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')

>>> import random
>>> @file_field_auto_delete('file')
... class FooModel(models.Model):
...     class Meta(object):
...         app_label = str(random.randrange(1000, 2000))
...     file = models.FileField(upload_to='foo')
Parameters:
  • fields (str, list) – Either a single file field which should be removed on delete or a list of fields. Also '*' can be used in order to delete all FileField on the model.
  • signal (Signal, optional) – Djagno signal class which should be used to attach the receiver signal handler to. By default is post_delete signal.
  • signal_name_pattern (str, optional) – The name given to the signal function which will automatically remove the file. This can be a string formatted string. Into it, two parameters will be passed which are model and field. model is a model class (not instance) to which the signal is being connected to and field is a name of the file field (or '_' delimited field names if multiple fields are given). The default pattern is post_delete_{model.__name__}_delete_{field} which results in patterns like 'post_delete_Model_delete_file_field'. The reason why this pattern might be useful is because it can be used to disconnect the signal receiver at a later time.
django_auxilium.models.signals.field_names

list – List of normalized field names which should be removed on change

django_auxilium.models.signals.fields

list – List of validated FieldSpec which signal will use to remove changed files

django_auxilium.models.signals.signal_name_pattern

str – Same as the signal_name_pattern parameter

django_auxilium.utils package
Subpackages
django_auxilium.utils.functools package
Submodules
django_auxilium.utils.functools.cache module
class django_auxilium.utils.functools.cache.BaseCache(parent, attr)[source]

Bases: object

Base class for implementing cache implementations

Parameters:
  • parent (object) – A parent object where cache is stored
  • attr (str) – Name of the attribute under which cache will be stored in the parent object
delete(*args, **kwargs)[source]

This method must be overwritten by subclasses which should delete cache value for the given parameters

args and kwargs are the parameters passed to the cached function and can be used by the method to determine which cache value from the parent object to remove

When cache value is not found, this method should raise NotInCache

get(*args, **kwargs)[source]

This method must be overwritten by subclasses which should return cache value

args and kwargs are the parameters passed to the cached function and can be used by the method to extract the cache value from the parent object

When cache value is not found, this method should raise NotInCache

set(value, *args, **kwargs)[source]

This method must be overwritten by subclasses which should set the cache for the given parameters

args and kwargs are the parameters passed to the cached function and can be used by the method to correctly store the cache value in the parent object

class django_auxilium.utils.functools.cache.BaseCacheDecorator(is_method=None)[source]

Bases: django_auxilium.utils.functools.decorators.HybridDecorator

Base decorator for caching callables so that they only execute once and all subsequent calls return cached value

This is very useful for expensive functions

cache_class

Caching implementation to use when wrapping standalone functions. This attribute is meant to be changed in subclasses.

alias of Caching

cache_descriptor_class = None

Descriptor class to be used when caching is applied to class methods. This attribute is meant to be changed in subclasses.

get_cache_descriptor()[source]

Hook for instantiating cache descriptor class

get_wrapped_object()[source]

Main method for wrapping the given object.

This method has separate code paths for the following scenarios:

Class method:When wrapping class method descriptor is returned as created by get_cache_descriptor(). That descriptor is then responsible for maintaining cache state for the class instance.
Function:When wrapping standalone function, this method returns a wrapping function which caches the value on this decorator instance. That means that the cache becomes global since functions in Python are singletons.
pop(*args, **kwargs)[source]

Method for popping cache value corresponding to the given parameters

class django_auxilium.utils.functools.cache.CacheDecorator(as_property=False, *args, **kwargs)[source]

Bases: django_auxilium.utils.functools.cache.BaseCacheDecorator

Decorator for caching callables so that they only execute once and all subsequent calls return cached value.

Note

This caching decorator does not account function parameters to cache values. If you need to cache different calls per given parameters, please look at MemoizeDecorator

Examples

When caching standalone functions:

>>> @CacheDecorator.as_decorator()
... def compute():
...     print('computing here')
...     return 'foo'

>>> print(compute())
computing here
foo
>>> print(compute())
foo

>>> print(compute.pop())
foo

>>> print(compute())
computing here
foo

When caching class methods:

>>> class Foo(object):
...     @CacheDecorator.as_decorator()
...     def foo(self):
...         print('computing here')
...         return 'foo'

>>> f = Foo()
>>> print(f.foo())
computing here
foo
>>> print(f.foo())
foo

>>> print(f.foo.pop())
foo

>>> print(f.foo())
computing here
foo
Parameters:as_property (bool) –

Boolean whether to create a property descriptor when using it on a class method

Warning

This is only meant to be used when the wrapping method does not accept any parameters since there is no way in Python to pass parameters to properties

cache_class

Caching implementation to use when wrapping standalone functions.

alias of Caching

cache_descriptor_class

Descriptor class to be used when caching is applied to class methods

alias of CacheDescriptor

get_cache_descriptor()[source]

Custom implementation for getting the cache descriptor which allows to use as_property parameter

class django_auxilium.utils.functools.cache.CacheDescriptor(method, cache_class=None, as_property=False)[source]

Bases: object

Cache descriptor to be used to add instance-level cache to class methods.

Note

This descriptor could be used independently (and there are even some examples below) however it is meant to be used along with CacheDecorator which provides much cleaner API.

Examples

>>> def bar(self):
...     print('computing')
...     return 'bar'

>>> class Foo(object):
...     foo = CacheDescriptor(bar)

>>> f = Foo()
>>> print(f.foo())
computing
bar
>>> print(f.foo())
bar
>>> print(f.foo.pop())
bar
>>> print(f.foo())
computing
bar
>>> f.foo.push('another value')
>>> print(f.foo())
another value
Parameters:
  • method (function) – Callable which this descriptor is meant to wrap and cache
  • cache_class (type, optional) – Caching implementation cache which should be used to apply caching. By default default_cache_class is used.
  • as_property (bool, optional) –

    Whether to implement the descriptor as a property. By default it is False.

    Warning

    This option as True can only be used with some caching implementations such as Caching. Other implementations do not suppose this.

cache_attribute_pattern = u'{name}_cache_{hash}'

String pattern for constructing the cache attribute name under which cache will be stored on the instance. This attribute is meant to be changed in subclasses to customize the functionality.

default_cache_class

Cache implementation class which will be used for the caching. This attribute is meant to be changed in subclasses to customize the functionality.

alias of Caching

get_cache(instance)[source]

Helper method which given returns cache implementation instance for the given instance with given parameters

getter(instance, *args, **kwargs)[source]

Wrapper method around the decorator-wrapped callable (method parameter) which returns cache value when available or otherwise computes and stores the value in cache by evaluating wrapped method

pop(instance, *args, **kwargs)[source]

Method for popping cache value corresponding to the given parameters from the instance as implemented by the caching implementation

push(instance, value, *args, **kwargs)[source]

Method for setting custom cache value given function parameters

class django_auxilium.utils.functools.cache.Caching(parent, attr)[source]

Bases: django_auxilium.utils.functools.cache.BaseCache

Caching implementation which stores single cache value on the parent object

The cache is simply stored on the given attribute. When the attribute is present on the parent object, that indicates that the cache was set and that value is used for cache. When not present, that means cache is missing and hence NotInCache is raised in most use-cases.

delete(*args, **kwargs)[source]

Delete the cache value from the parent object

Raises:NotInCache – When the cache is not set and so cannot be deleted
get(*args, **kwargs)[source]

Get the cache value from the parent object

Raises:NotInCache – When the cache is not set
set(value, *args, **kwargs)[source]

Store the cache value on the parent object

class django_auxilium.utils.functools.cache.MemoizeDecorator(is_method=None)[source]

Bases: django_auxilium.utils.functools.cache.BaseCacheDecorator

Decorator for memoizing functions so that they only execute once and all subsequent calls with same parameters

This is very useful for expensive functions which accept parameters

Examples

When caching standalone functions:

>>> @MemoizeDecorator.as_decorator()
... def compute(x):
...     print('computing for', x)
...     return x + 'foo'

>>> print(compute('bar'))
computing for bar
barfoo
>>> print(compute('awesome'))
computing for awesome
awesomefoo
>>> print(compute('bar'))
barfoo

>>> print(compute.pop('bar'))
barfoo

>>> print(compute('bar'))
computing for bar
barfoo
>>> print(compute('awesome'))
awesomefoo

When caching class methods:

>>> class Foo(object):
...     @MemoizeDecorator.as_decorator()
...     def foo(self, x):
...         print('computing for', x)
...         return x + 'foo'

>>> f = Foo()
>>> print(f.foo('bar'))
computing for bar
barfoo
>>> print(f.foo('awesome'))
computing for awesome
awesomefoo

>>> print(f.foo('bar'))
barfoo
>>> print(f.foo('awesome'))
awesomefoo

>>> print(f.foo.pop('bar'))
barfoo

>>> print(f.foo('bar'))
computing for bar
barfoo
>>> print(f.foo('awesome'))
awesomefoo
cache_class

Caching implementation to use when wrapping standalone functions.

alias of Memoizing

cache_descriptor_class

Descriptor class to be used when caching is applied to class methods

alias of MemoizeDescriptor

class django_auxilium.utils.functools.cache.MemoizeDescriptor(method, cache_class=None, as_property=False)[source]

Bases: django_auxilium.utils.functools.cache.CacheDescriptor

Cache descriptor to be used to add instance-level cache to class methods which considers method parameters when caching values.

In other words, this descriptor caches method results per given parameters.

Note

This descriptor could be used independently (and there are even some examples below) however it is meant to be used along with MemoizeDecorator which provides much cleaner API.

Examples

>>> def bar(self, x):
...     print('computing for', x)
...     return x + 'bar'

>>> class Foo(object):
...     foo = MemoizeDescriptor(bar)

>>> f = Foo()
>>> print(f.foo('foo'))
computing for foo
foobar
>>> print(f.foo('awesome'))
computing for awesome
awesomebar
>>> print(f.foo('foo'))
foobar
>>> print(f.foo.pop('foo'))
foobar
>>> print(f.foo('foo'))
computing for foo
foobar
>>> print(f.foo('awesome'))
awesomebar
cache_attribute_pattern = u'{name}_memoize_{hash}'

String pattern for constructing the cache attribute name under which cache will be stored on the instance. This attribute is meant to be changed in subclasses to customize the functionality.

default_cache_class

Cache implementation class which will be used for the caching. This attribute is meant to be changed in subclasses to customize the functionality.

alias of Memoizing

class django_auxilium.utils.functools.cache.Memoizing(parent, attr)[source]

Bases: django_auxilium.utils.functools.cache.BaseCache

Caching implementation which stores single cache value for a set of given parameters on the parent object hence is called memoization

The cache is stored on the given attribute as a dictionary. Keys are string representations of the given parameters to the cached function and the values are their corresponding cache values. When the key is in the dictionary, that is used as cache value. Otherwise, in most cases NotInCache is raised.

delete(*args, **kwargs)[source]

Delete the cache value from the parent object for the key as computed by the given parameters

Raises:NotInCache – When the cache is not set and so cannot be deleted
get(*args, **kwargs)[source]

Get the cache value from the parent object by computing the key from the given parameters

Raises:NotInCache – When the cache is not set
set(value, *args, **kwargs)[source]

Store the cache value on the parent object for the key as computed for the given parameters

exception django_auxilium.utils.functools.cache.NotInCache[source]

Bases: exceptions.Exception

Exception for when a value is not present in cache.

Primary purpose of the exception is to normalize various exception types from different cache implementations.

django_auxilium.utils.functools.cache.cache(*args, **kwargs)

Decorator for caching callables so that they only execute once and all subsequent calls return cached value.

Note

This caching decorator does not account function parameters to cache values. If you need to cache different calls per given parameters, please look at MemoizeDecorator

Examples

When caching standalone functions:

>>> @CacheDecorator.as_decorator()
... def compute():
...     print('computing here')
...     return 'foo'

>>> print(compute())
computing here
foo
>>> print(compute())
foo

>>> print(compute.pop())
foo

>>> print(compute())
computing here
foo

When caching class methods:

>>> class Foo(object):
...     @CacheDecorator.as_decorator()
...     def foo(self):
...         print('computing here')
...         return 'foo'

>>> f = Foo()
>>> print(f.foo())
computing here
foo
>>> print(f.foo())
foo

>>> print(f.foo.pop())
foo

>>> print(f.foo())
computing here
foo
Parameters:as_property (bool) –

Boolean whether to create a property descriptor when using it on a class method

Warning

This is only meant to be used when the wrapping method does not accept any parameters since there is no way in Python to pass parameters to properties

django_auxilium.utils.functools.cache.cache_method(*args, **kwargs)

Shortcut for cache which automatically indicates that the cached object is a method.

These are equivalent:

class Foo(object):
    @cache(is_method=True)
    def foo(self): pass

class Foo(object):
    @cache_method
    def bar(self): pass
django_auxilium.utils.functools.cache.cache_property(*args, **kwargs)

Shortcut for cache which automatically creates properties when used on class methods.

These are equivalent:

@cache(as_property=True)
def foo(self): pass

@cache_property
def bar(self): pass
django_auxilium.utils.functools.cache.memoize(*args, **kwargs)

Decorator for memoizing functions so that they only execute once and all subsequent calls with same parameters

This is very useful for expensive functions which accept parameters

Examples

When caching standalone functions:

>>> @MemoizeDecorator.as_decorator()
... def compute(x):
...     print('computing for', x)
...     return x + 'foo'

>>> print(compute('bar'))
computing for bar
barfoo
>>> print(compute('awesome'))
computing for awesome
awesomefoo
>>> print(compute('bar'))
barfoo

>>> print(compute.pop('bar'))
barfoo

>>> print(compute('bar'))
computing for bar
barfoo
>>> print(compute('awesome'))
awesomefoo

When caching class methods:

>>> class Foo(object):
...     @MemoizeDecorator.as_decorator()
...     def foo(self, x):
...         print('computing for', x)
...         return x + 'foo'

>>> f = Foo()
>>> print(f.foo('bar'))
computing for bar
barfoo
>>> print(f.foo('awesome'))
computing for awesome
awesomefoo

>>> print(f.foo('bar'))
barfoo
>>> print(f.foo('awesome'))
awesomefoo

>>> print(f.foo.pop('bar'))
barfoo

>>> print(f.foo('bar'))
computing for bar
barfoo
>>> print(f.foo('awesome'))
awesomefoo
django_auxilium.utils.functools.decorators module

Collection of simple utilities which modify some behaviour of functions

class django_auxilium.utils.functools.decorators.Decorator[source]

Bases: object

Base class for various decorators.

Its aim is to do the same for decorators as Django class-based-views did to function-based-views.

The most common pattern for creating decorators in Python can be summarized in the following snippet:

from functools import wraps
def decorator(f):
    @wraps(f)
    def wrapper(*args, **args):
        # some logic here
        return f(*args, **kwargs)
    return wrapper

The problem with the above approach is when decorators need to employ more difficult logic. That sometimes can cause decorator functions to become big hence making it difficult to maintain and test. This class is meant to simplify this task. It provides a way to make decorators by using classes. Its aim is to do the same for decorators as Django class-based-views did to function-based-views. This means that decorator’s various functionality can be split among class methods which can make the decorator’s logic more transparent and more test-friendly. It also automatically wraps the decorated object using functools.wraps saving some coding lines. Finally, this class allows to create decorators where initializing the decorator is optional. This perhaps can better be illustrated in a snippet:

@decorator             # not initialized
def happy(): pass

@decorator(foo='bar')  # initialized
def bunnies(): pass

Using this class is pretty simple. The most useful method you should know is get_wrapped_object(). Inside the method you can refer to to_wrap which is the object the method should wrap. The method itself should return the wrapped version of the to_wrap object. If your decorator needs to accept additional parameters, you can overwrite decorators __init__. Finally, to use the decorator, don’t forget to use the as_decorator() class method. You can refer to Examples to see a more full example of how to use this class.

Examples

>>> class D(Decorator):
...     def __init__(self, happy=False):
...         self.happy = happy
...     def get_wrapped_object(self):
...         def wrapped(*args, **kwargs):
...             print('called wrapped with', args, kwargs)
...             if self.happy:
...                 print('Bunnies are very happy today!')
...             return self.to_wrap(*args, **kwargs)
...         return wrapped
...
>>> decorator = D.as_decorator()

>>> # not initialized (default values will be used if defined)
>>> @decorator
... def sum(a, b):
...    return a + b

>>> sum(5, 6)
called wrapped with (5, 6) {}
11

>>> # initialized with no parameters (default values will be used if defined)
>>> @decorator()
... def sum(a, b):
...    return a + b

>>> sum(7, 8)
called wrapped with (7, 8) {}
15

>>> # initialized with keyword parameters
>>> @decorator(happy=True)
... def sum(a, b):
...    "Sum function"
...    return a + b

>>> sum(9, 10)
called wrapped with (9, 10) {}
Bunnies are very happy today!
19

>>> sum.__doc__ == 'Sum function'
True
to_wrap

object – The object to be decorated/wrapped. This attributes becomes available when the decorator is called on the object.

classmethod as_decorator(*a, **kw)[source]

Return the actual decorator.

This method is necessary because the decorator is a class. Consider the following:

>>> class ClassDecorator(object):
...     def __init__(self, obj):
...         self.to_wrap = obj

>>> @ClassDecorator
... def foo(): pass
>>> isinstance(foo, ClassDecorator)
True

In the above, since foo will be passed to the decorator’s class __init__, the returned object will be an instance of the decorator’s class instead of a wrapper function. To avoid that, this method constructs a wrapper function which guarantees that the output of the decorator will be the wrapped object:

>>> class D(Decorator):
...     pass
>>> d = D.as_decorator()
>>> @d
... def foo(): pass
>>> isinstance(foo, D)
False
get_wrapped_object()[source]

Returns the wrapped version of the object to be decorated/wrapped.

This is the meat of class because this method is the one which creates the decorator. Inside the method, you can refer to the object to be decorated via self.to_wrap.

Note

This class automatically uses the functools.wraps to preserve the to_wrap’s object useful attributes such as __doc__ hence there is no need to do that manually. You can just return a wrapped object and the class will take care of the rest.

Returns:f – Decorated/wrapped function
Return type:object
pre_wrap()[source]

Hook for executing things before wrapping objects

class django_auxilium.utils.functools.decorators.HybridDecorator(is_method=None)[source]

Bases: django_auxilium.utils.functools.decorators.Decorator

Class for implementing decorators which can decorate both regular functions as well as class methods.

This decorator automatically determines if the object to be decorated is a stand-alone function or a class method by adding an in_class attribute.

Parameters:is_method (bool, optional) – Explicitly specify whether the decorator is being used on class method or a standalone function. When not specified, pre_wrap() is used to automatically determine that. Please look at its documentation for the explanation of its limitations.
in_class

boolTrue if the object to be decorated is a class method, or False if it is a standalone function

pre_wrap()[source]

Method which determines whether the to_wrap is a class method or a standalone function

Warning

This method uses pretty primitive technique to determine whether the wrapped callable is a class method or a function and so it might not work in all cases. It checks the first parameter name of the callable and if it is either 'self' or 'cls' it is most likely a method.

If you need more precise behavior you are encouraged to use is_method decorator parameter.

django_auxilium.utils.functools.lazy module
class django_auxilium.utils.functools.lazy.LazyDecorator(types)[source]

Bases: django_auxilium.utils.functools.decorators.Decorator

Lazy evaluation decorator.

Parameters:types (tuple, list) – Iterable of possible output data-types of the output of the input function

Examples

>>> lazy = LazyDecorator

>>> @lazy([six.string_types, int])
... def a(bar):
...   print('invoking a with {0}'.format(bar))
...   if isinstance(bar, int):
...       return bar + 5
...   else:
...       return bar + 'foo'

>>> l = a('bar')
>>> isinstance(l, six.string_types)
invoking a with bar
True
>>> print(l)
barfoo

>>> l = a(5)
>>> isinstance(l, int)
invoking a with 5
True
>>> print(l)
10
get_lazy_wrapper_class()[source]

Construct lazy wrapper class for the given possible types

Returns:Lazy wrapper class specifically made for the possible types
Return type:type
get_possible_types(possible_types)[source]

Get possible types as a list

Parameters:possible_types (list, any) – Either a list of possible types or a single possible type
Returns:List of possible types. If the input possible_types was given as a single possible types, a list with a single item is returned.
Return type:list
get_wrapped_object()[source]

Get the wrapped callable which instead of computing values right away returns a lazy wrapper.

class django_auxilium.utils.functools.lazy.LazyWrapper(f, args, kwargs)[source]

Bases: django.utils.functional.Promise

Wrapper class for lazy objects as returned by the LazyDecorator

The job of this wrapper is to not execute the inner function to get the result until absolutely necessary. For example simply storing a variable will not trigger inner function to be executed until something is done with the variable such as printing it, etc.

Parameters:
  • f (def) – Function which this lazy object wraps
  • args (tuple) – Tuple of arguments which were passed to the function for execution
  • kwargs (dict) – Dict of keyword arguments which were passed to the function for execution
class django_auxilium.utils.functools.lazy.LazyWrapperMeta[source]

Bases: type

Metaclass for LazyWrapper

The reason we need metaclass is because we need to customize some magic methods for LazyWrapper for particular types while creating class which is what metaclasses are for!

This metaclass expects all subclasses of LazyWrapper to supply possible_types attribute which this metaclass will use to customize the created class.

django_auxilium.utils.functools.lazy.SPECIAL_METHODS = ['__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__', '__contains__', '__delitem__', '__delslice__', '__div__', '__divmod__', '__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__', '__idiv__', '__idivmod__', '__ifloordiv__', '__ilshift__', '__imod__', '__imul__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rfloorfiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setitem__', '__setslice__', '__str__', '__sub__', '__truediv__', '__unicode__', '__xor__', 'next']

The list of special methods is compiled from http://code.activestate.com/recipes/496741-object-proxying/

django_auxilium.utils.functools.lazy.flazy(f, possible_types)[source]

Wrapper function for the LazyDecorator

It has the same API as Django’s lazy function so the same code can be reused with this decorator if necessary.

Examples

>>> def f():
...     print('inside f')
...     return 5
>>> g = flazy(f, int)
>>> h = g()
>>> print(str(h))
inside f
5
django_auxilium.utils.functools.lazy.lazy

alias of django_auxilium.utils.functools.lazy.LazyDecorator

Submodules
django_auxilium.utils.content_type module
django_auxilium.utils.content_type.get_content_type(f)[source]

Get content_type of a file by using magic library

Parameters:f (str or file) – Either a binary string of a file content or a file-like object from which file data will be read
Returns:Content-type of a file as string
Return type:str
django_auxilium.utils.content_type.get_content_type_from_binary(data)[source]

Get content_type of a binary string by using magic library

Parameters:data (binary) – Binary string data of a file from which content_type will be determined
Returns:Content-type of a file as string
Return type:str
django_auxilium.utils.content_type.get_content_type_from_file(f)[source]

Get content_type of a file-like object by using magic library

Note

This function reads first 1Kb of the file in order to determine the content_type however at the end seeks back to 0

Parameters:f (file) – File-like object which should implement .seek() and .read() methods from which content_type will be determined
Returns:Content-type of a file as string
Return type:str
django_auxilium.utils.html module
class django_auxilium.utils.html.TextExtractorHTMLParser[source]

Bases: HTMLParser.HTMLParser

Custom HTML parser which extracts only text while parsing HTML

Once the parser parses the HTML, get_text() can be called which will return extracted text

get_text()[source]

Get extracted text after HTML is parsed.

Returns:Extracted text from the HTML document
Return type:str
handle_charref(number)[source]

Handler for processing character references.

This method handles both decimal (e.g. '&gt;' == '&#62;') and hexadecimal (e.g. '&gt;' == '&#x3E;') references. It does that by simply converting the reference number to an integer with appropriate base and then converts that number to a character.

handle_data(d)[source]

Handler for data/text in HTML

This simply adds the data to the results list this class maintains of the extracted html

handle_entityref(name)[source]

Handler for processing character references.

This method handles processing HTML entities (e.g. '&gt;'). It first maps the entity name to a codepoint which is a unicode character number and then converts that number to a unicode character.

django_auxilium.utils.html.html_to_text(html)[source]

Function to convert HTML text to plain text by stripping all HTML.

Implementation is based from http://stackoverflow.com/questions/753052/strip-html-from-strings-in-python.

django_auxilium.utils.html.simple_minify(string)[source]

Minify HTML with very simple algorithm.

This function tries to minify HTML by stripping most spaces between all html tags (e.g. </div>    <div> -> </div> <div>). Note that not all spaces are removed since sometimes that can adjust rendered HTML (e.g. <strong>Hello</strong> <i></i>). In addition to that, this function replaces all whitespace (more then two consecutive whitespace characters or new line) with a space character except inside excluded tags such as pre or textarea.

Though process:

To minify everything except content of excluded tags in one step requires very complex regular expression. The disadvantage is the regular expression will involve look-behinds and look-aheads. Those operations make regex much more resource-hungry which eats precious server resources. In addition, complex regex are hard to understand and can be hard to maintain. That is why this function splits the task into multiple sections.

  1. Regex expression which matches all exclude tags within the html is used to split the HTML split into components. Since the regex expression is wrapped inside a group, the content of the exclude tags is also included inside the resulting split list. Due to that it is guaranteed that every odd element (if there are any) will be the excluded tags.
  2. All the split components are looped and processed in order to construct final minified HTML.
  3. All odd indexed elements are not processed and are simply appended to final HTML since as explained above, they are guaranteed to be content of excluded tags hence do not require minification.
  4. All even indexed elements are minified by stripping whitespace between tags and redundant whitespace is stripped in general via simple regex.

You can notice that the process does not involve parsing HTML since that usually adds some overhead (e.g. using beautiful soup). By using 2 regex passes this achieves very similar result which performs much better.

django_auxilium.utils.range module
class django_auxilium.utils.range.AlphabeticNumbers[source]

Bases: object

Utility class for dealing with numbers in alphabetical form. Useful for converting Excel column notation into numbers and vise verse.

static int_from_str(string)[source]

Convert alphabetical number into actual integer.

Parameters:string (str) – Number in alphabetical form (e.g. AB = 28)
Returns:number – Converted integer value
Return type:int
static str_from_int(number)[source]

Convert integer into its alphabetical representation.

Parameters:number (int) – Number to be converted
Returns:string – The alphabetical representation of the number
Return type:str
Raises:ValueError – If the input number is not valid
class django_auxilium.utils.range.Range[source]

Bases: django_auxilium.utils.range.rangenamedtuple

Helper data-structure for storing excel-type ranges.

Also has some useful range-related properties

columns

Gets the number of columns in a given range.

Returns:columns – The number of columns
Return type:int
rows

Gets the number of columns in a given range.

Returns:columns – The number of columns
Return type:int
django_auxilium.utils.string module
class django_auxilium.utils.string.TextOnion[source]

Bases: django_auxilium.utils.functools.decorators.Decorator

Simple text onion decorator.

This decorator ensures that the decorated function always receives text string even if the decorator receives binary text. Once the wrapped function computes the result, decorator returns the same data-type as it has received.

get_wrapped_object()[source]
django_auxilium.utils.string.text_onion(*args, **kwargs)

Simple text onion decorator.

This decorator ensures that the decorated function always receives text string even if the decorator receives binary text. Once the wrapped function computes the result, decorator returns the same data-type as it has received.

django_auxilium.views package
Submodules
django_auxilium.views.wizard module
class django_auxilium.views.wizard.WizardView(**kwargs)[source]

Bases: formtools.wizard.views.WizardView

Modified Django’s WizardView which allows to specify form_list as class attribute.

When using Django’s WizardView, the form_list must be specified when calling as_view():

WizardView.as_view(form_list)

This class allows to provide the form_list as class attribute:

Wizard(WizardView):
    form_list = []

Wizard.as_view()

Warning

This class requires django-formtools to be independently installed since this library does not install it as a dependency.

form_list = []
classmethod get_initkwargs(*args, **kwargs)[source]

Custom get_initkwargs which adds form_list to the super call when class defines any forms.

Django Auxilium

PyPI version Build Status Coverage

About

Django Auxilium is a set of utilities packages as a Django app which help working with Django. The word “auxilium” means help in Latin. How this project came about is because I used to have an app for each of my Django projects called core or common where I kept all of my utility methods and classes, but after doing a couple of projects, maintaining the same folder within all of the project became non-productive, hence I refactored it into a separate reusable package.

Docs

For some of the highlights about the library and the most useful features you are encouraged to take a look at the documentation, particularly Highlights document.

Installation

Easiest way to install is by using pip:

$ pip install django-auxilium

If you want to install from source code, you can also install using setup tools:

$ python setup.py install

Tests

Before running tests you need to install all test dependencies:

$ pip install -r requirements-dev.txt
# or
$ make install

Then to run tests you can use Makefile:

$ make test

Note

This library uses both functional and doctests

Indices and tables