Completed
Pull Request — master (#71)
by Johannes
01:13
created

stdimage.management.commands.class_to_path()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 2
rs 10
1
# -*- coding: utf-8 -*-
2
from __future__ import absolute_import, unicode_literals
3
4
import resource
5
import sys
6
import traceback
7
from multiprocessing import Pool, cpu_count
8
9
import progressbar
10
from django.apps import apps
11
from django.core.files.storage import get_storage_class
12
from django.core.management import BaseCommand
13
14
from stdimage.utils import render_variations
15
16
BAR = None
17
18
19
class MemoryUsageWidget(progressbar.widgets.WidgetBase):
20
    def __call__(self, progress, data):
21
        return 'RAM: {0:10.1f} MB'.format(
22
            resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024
23
        )
24
25
26
class Command(BaseCommand):
27
    help = 'Renders all variations of a StdImageField.'
28
    args = '<app.model.field app.model.field>'
29
30
    def add_arguments(self, parser):
31
        parser.add_argument('--replace',
32
                            action='store_true',
33
                            dest='replace',
34
                            default=False,
35
                            help='Replace existing files.')
36
37
    def handle(self, *args, **options):
38
        replace = options.get('replace')
39
        for route in args:
40
            app_label, model_name, field_name = route.rsplit('.')
41
            model_class = apps.get_model(app_label, model_name)
42
            field = model_class._meta.get_field(field_name)
43
44
            queryset = model_class._default_manager \
45
                .exclude(**{'%s__isnull' % field_name: True}) \
46
                .exclude(**{field_name: ''})
47
            images = queryset.values_list(field_name, flat=True).iterator()
48
            count = queryset.count()
49
50
            self.render(field, images, count, replace)
51
52
    @staticmethod
53
    def render(field, images, count, replace):
54
        pool = Pool(
55
            initializer=init_progressbar,
56
            initargs=[count]
57
        )
58
        args = [
59
            dict(
60
                file_name=file_name,
61
                variations=field.variations,
62
                replace=replace,
63
                storage=field.storage.deconstruct()[0],
64
            )
65
            for file_name in images
66
        ]
67
        pool.map(render_field_variations, args)
68
        pool.apply(finish_progressbar)
69
        pool.close()
70
        pool.join()
71
72
73
def init_progressbar(count):
74
    global BAR
75
    BAR = progressbar.ProgressBar(maxval=count, widgets=(
76
        progressbar.RotatingMarker(),
77
        ' | ', MemoryUsageWidget(),
78
        ' | CPUs: {}'.format(cpu_count()),
79
        ' | ', progressbar.AdaptiveETA(),
80
        ' | ', progressbar.Percentage(),
81
        ' ', progressbar.Bar(),
82
    ))
83
84
85
def finish_progressbar():
86
    BAR.finish()
87
88
89
def render_field_variations(kwargs):
90
    try:
91
        kwargs['storage'] = get_storage_class(kwargs['storage'])()
92
        render_variations(**kwargs)
93
        global BAR
94
        BAR += 1
95
    except:
96
        raise Exception("".join(traceback.format_exception(*sys.exc_info())))
97