Skip to content

Allow management command to ignore missing file #191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,12 @@ class AsyncImageModel(models.Model)
You might want to add new variations to a field. That means you need to render new variations for missing fields.
This can be accomplished using a management command.
```bash
python manage.py rendervariations 'app_name.model_name.field_name' [--replace]
python manage.py rendervariations 'app_name.model_name.field_name' [--replace] [-i/--ignore-missing]
```
The `replace` option will replace all existing files.
The `ignore-missing` option will suspend missing source file errors and keep
rendering variations for other files. Othervise command will stop on first
missing file.

### Multi processing
Since version 2 stdImage supports multiprocessing.
Expand Down
31 changes: 24 additions & 7 deletions stdimage/management/commands/rendervariations.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,16 @@ def add_arguments(self, parser):
default=False,
help='Replace existing files.')

parser.add_argument('-i', '--ignore-missing',
action='store_true',
dest='ignore_missing',
default=False,
help='Ignore missing source file error and '
'skip render for that file')

def handle(self, *args, **options):
replace = options.get('replace', False)
ignore_missing = options.get('ignore_missing', False)
routes = options.get('field_path', [])
for route in routes:
try:
Expand All @@ -48,10 +56,11 @@ def handle(self, *args, **options):
images = queryset.values_list(field_name, flat=True).iterator()
count = queryset.count()

self.render(field, images, count, replace, do_render)
self.render(field, images, count, replace, ignore_missing,
do_render)

@staticmethod
def render(field, images, count, replace, do_render):
def render(field, images, count, replace, ignore_missing, do_render):
kwargs_list = (
dict(
file_name=file_name,
Expand All @@ -60,6 +69,7 @@ def render(field, images, count, replace, do_render):
replace=replace,
storage=field.storage.deconstruct()[0],
field_class=field.attr_class,
ignore_missing=ignore_missing,
)
for file_name in images
)
Expand All @@ -77,9 +87,16 @@ def render(field, images, count, replace, do_render):

def render_field_variations(kwargs):
kwargs['storage'] = get_storage_class(kwargs['storage'])()
ignore_missing = kwargs.pop('ignore_missing')
do_render = kwargs.pop('do_render')
if callable(do_render):
kwargs.pop('field_class')
do_render = do_render(**kwargs)
if do_render:
render_variations(**kwargs)
try:
if callable(do_render):
kwargs.pop('field_class')
do_render = do_render(**kwargs)
if do_render:
render_variations(**kwargs)
except FileNotFoundError as e:
if not ignore_missing:
raise CommandError(
'Source file was not found, terminating. '
'Use -i/--ignore-missing to skip this error.') from e
42 changes: 42 additions & 0 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,48 @@ def test_replace(self, image_upload_file):
after = os.path.getmtime(file_path)
assert before != after

def test_ignore_missing(self, image_upload_file):
obj = ThumbnailModel.objects.create(image=image_upload_file)
file_path = obj.image.path
assert os.path.exists(file_path)
os.remove(file_path)
assert not os.path.exists(file_path)
time.sleep(1)
call_command(
'rendervariations',
'tests.ThumbnailModel.image',
'--ignore-missing',
replace=True,
)

def test_short_ignore_missing(self, image_upload_file):
obj = ThumbnailModel.objects.create(image=image_upload_file)
file_path = obj.image.path
assert os.path.exists(file_path)
os.remove(file_path)
assert not os.path.exists(file_path)
time.sleep(1)
call_command(
'rendervariations',
'tests.ThumbnailModel.image',
'-i',
replace=True,
)

def test_no_ignore_missing(self, image_upload_file):
obj = ThumbnailModel.objects.create(image=image_upload_file)
file_path = obj.image.path
assert os.path.exists(file_path)
os.remove(file_path)
assert not os.path.exists(file_path)
time.sleep(1)
with pytest.raises(CommandError):
call_command(
'rendervariations',
'tests.ThumbnailModel.image',
replace=True,
)

def test_none_default_storage(self, image_upload_file):
obj = MyStorageModel.customer_manager.create(
image=image_upload_file
Expand Down