diff --git a/.travis.yml b/.travis.yml index 0cf3e5c..eb18fac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,32 +1,29 @@ language: python sudo: false python: - - "2.6" - "2.7" - - "3.2" - "3.3" - "3.4" - "pypy" - "pypy3" env: - - DJANGO="<1.6,>=1.5" - DJANGO="<1.7,>=1.6" - DJANGO="<1.8,>=1.7" - DJANGO="<1.9,>=1.8" matrix: allow_failures: - - env: DJANGO="<1.6,>=1.5" - env: DJANGO="<1.7,>=1.6" - python: "2.6" - python: "3.2" install: - - pip install --upgrade pip + - pip install -U pip - pip install . - pip install Django$DJANGO - - pip install pytest pytest-pep8 pytest-flakes + - pip install -U pytest pytest-pep8 pytest-flakes pytest-isort pep257 - pip install coveralls script: - coverage run --source=stdimage runtests.py + - coverage run --source=stdimage runtests.py + - pep257 stdimage after_success: coveralls diff --git a/README.rst b/README.rst index 3485eb6..465a967 100644 --- a/README.rst +++ b/README.rst @@ -26,7 +26,6 @@ Django Field that implement the following features: * Django-Storages compatible (S3) * Python 2, 3 and PyPy support -* Django 1.5 and later support * Resize images to different sizes * Access thumbnails on model level, no template tags required * Preserves original image diff --git a/pytest.ini b/pytest.ini index 37a9140..be372c8 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,7 +1,7 @@ [pytest] norecursedirs=venv DJANGO_SETTINGS_MODULE=tests.settings -addopts = --tb=short --pep8 --flakes -rxs +addopts = --tb=short --pep8 --isort --flakes -rxs pep8ignore= setup.py ALL runtests.py ALL diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..50e382c --- /dev/null +++ b/setup.cfg @@ -0,0 +1,6 @@ +[pep257] +verbose = true +explain = true +source = true +count = true +ignore = D100,D101,D102,D103 diff --git a/stdimage/management/commands/rendervariations.py b/stdimage/management/commands/rendervariations.py index f94dca2..d0d8318 100644 --- a/stdimage/management/commands/rendervariations.py +++ b/stdimage/management/commands/rendervariations.py @@ -76,14 +76,13 @@ def init_progressbar(count): def finish_progressbar(): - global BAR BAR.finish() def render_field_variations(kwargs): try: - global BAR render_variations(**kwargs) + global BAR BAR += 1 except: raise Exception("".join(traceback.format_exception(*sys.exc_info()))) diff --git a/stdimage/models.py b/stdimage/models.py index ffc60fe..d62092b 100644 --- a/stdimage/models.py +++ b/stdimage/models.py @@ -18,10 +18,8 @@ class StdImageFileDescriptor(ImageFileDescriptor): - """ - The variation property of the field should be accessible in instance cases - """ + """The variation property of the field is accessible in instance cases.""" def __set__(self, instance, value): super(StdImageFileDescriptor, self).__set__(instance, value) @@ -29,9 +27,8 @@ def __set__(self, instance, value): class StdImageFieldFile(ImageFieldFile): - """ - Like ImageFieldFile but handles variations. - """ + + """Like ImageFieldFile but handles variations.""" def save(self, name, content, save=True): super(StdImageFieldFile, self).save(name, content, save) @@ -57,18 +54,14 @@ def is_smaller(img, variation): or img.size[1] > variation['height'] def render_variations(self, replace=False): - """ - Renders all image variations and saves them to the storage - """ - for key, variation in self.field.variations.items(): + """Render all image variations and saves them to the storage.""" + for _, variation in self.field.variations.items(): self.render_variation(self.name, variation, replace, self.storage) @classmethod def render_variation(cls, file_name, variation, replace=False, storage=DefaultStorage()): - """ - Renders an image variation and saves it to the storage - """ + """Render an image variation and saves it to the storage.""" variation_name = cls.get_variation_name(file_name, variation['name']) if storage.exists(variation_name): if replace: @@ -118,10 +111,7 @@ def render_variation(cls, file_name, variation, replace=False, @classmethod def get_variation_name(cls, file_name, variation_name): - """ - Returns the variation file name based on the model - it's field and it's variation. - """ + """Return the variation file name based on the variation.""" ext = cls.get_file_extension(file_name) path = file_name.rsplit('/', 1)[0] file_name = file_name.rsplit('/', 1)[-1].rsplit('.', 1)[0] @@ -134,9 +124,7 @@ def get_variation_name(cls, file_name, variation_name): @staticmethod def get_file_extension(filename): - """ - Returns the file extension. - """ + """Return the file extension.""" return os.path.splitext(filename)[1].lower() def delete(self, save=True): @@ -150,13 +138,25 @@ def delete_variations(self): class StdImageField(ImageField): + """ - Django field that behaves as ImageField, with some extra features like: - - Auto resizing - - Allow image deletion + Django ImageField that is able to create different size variations. + + Extra features are: + - Django-Storages compatible (S3) + - Python 2, 3 and PyPy support + - Django 1.5 and later support + - Resize images to different sizes + - Access thumbnails on model level, no template tags required + - Preserves original image + - Asynchronous rendering (Celery & Co) + - Multi threading and processing for optimum performance + - Restrict accepted image dimensions + - Rename files to a standardized name (using a callable upload_to) :param variations: size variations of the image """ + descriptor_class = StdImageFileDescriptor attr_class = StdImageFieldFile def_variation = { @@ -170,7 +170,8 @@ def __init__(self, verbose_name=None, name=None, variations=None, render_variations=True, force_min_size=False, *args, **kwargs): """ - Standardized ImageField for Django + Standardized ImageField for Django. + Usage: StdImageField(upload_to='PATH', variations={'thumbnail': {"width", "height", "crop", "resample"}}) :param variations: size variations of the image @@ -222,7 +223,8 @@ def add_variation(self, name, params): def set_variations(self, instance=None, **kwargs): """ - Creates a "variation" object as attribute of the ImageField instance. + Create a "variation" object as attribute of the ImageField instance. + Variation attribute will be of the same class as the original image, so "path", "url"... properties can be used @@ -242,7 +244,7 @@ def set_variations(self, instance=None, **kwargs): setattr(field, name, variation_field) def contribute_to_class(self, cls, name): - """Call methods for generating all operations on specified signals""" + """Generating all operations on specified signals.""" super(StdImageField, self).contribute_to_class(cls, name) signals.post_init.connect(self.set_variations, sender=cls) diff --git a/stdimage/utils.py b/stdimage/utils.py index e1b8ec8..a446d8a 100644 --- a/stdimage/utils.py +++ b/stdimage/utils.py @@ -88,9 +88,7 @@ def pre_save_delete_callback(sender, instance, **kwargs): def render_variations(file_name, variations, replace=False, storage=DefaultStorage()): - """ - Renders all variations for a given field. - """ + """Render all variations for a given field.""" for key, variation in variations.items(): StdImageFieldFile.render_variation( file_name, variation, replace, storage diff --git a/stdimage/validators.py b/stdimage/validators.py index cdc4515..5034652 100644 --- a/stdimage/validators.py +++ b/stdimage/validators.py @@ -10,9 +10,9 @@ class BaseSizeValidator(BaseValidator): - """ - Base validator that validates the size of an image. - """ + + """Base validator that validates the size of an image.""" + compare = lambda self, x: True def __init__(self, width, height): @@ -36,11 +36,13 @@ def clean(value): class MaxSizeValidator(BaseSizeValidator): + """ ImageField validator to validate the max with and height of an image. You may use float("inf") as an infinite boundary. """ + compare = lambda self, img_size, max_size:\ img_size[0] > max_size[0] or img_size[1] > max_size[1] message = _('The image you uploaded is too large.' @@ -50,11 +52,13 @@ class MaxSizeValidator(BaseSizeValidator): class MinSizeValidator(BaseSizeValidator): + """ ImageField validator to validate the min with and height of an image. You may use float("inf") as an infinite boundary. """ + compare = lambda self, img_size, min_size:\ img_size[0] < min_size[0] or img_size[1] < min_size[1] message = _('The image you uploaded is too small.'