From 489936d2914cd3b67ec101b2a59498f3dfd56aae Mon Sep 17 00:00:00 2001 From: Simon Conseil Date: Wed, 3 Jan 2018 19:16:16 +0100 Subject: [PATCH 1/5] pep8 --- sigal/__init__.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sigal/__init__.py b/sigal/__init__.py index 70e82d0..af754ff 100644 --- a/sigal/__init__.py +++ b/sigal/__init__.py @@ -199,15 +199,13 @@ def serve(destination, port, config): settings = read_settings(config) destination = settings.get('destination') if not os.path.exists(destination): - sys.stderr.write("The '{}' directory doesn't exist, " - "maybe try building first?" - "\n".format(destination)) + sys.stderr.write("The '{}' directory doesn't exist, maybe try " + "building first?\n".format(destination)) sys.exit(1) else: sys.stderr.write("The {destination} directory doesn't exist " - "and the config file ({config}) could not be " - "read." - "\n".format(destination=destination, config=config)) + "and the config file ({config}) could not be read.\n" + .format(destination=destination, config=config)) sys.exit(2) print('DESTINATION : {}'.format(destination)) @@ -224,6 +222,7 @@ def serve(destination, port, config): except KeyboardInterrupt: print('\nAll done!') + @main.command() @argument('target') @argument('keys', nargs=-1) @@ -257,6 +256,6 @@ def set_meta(target, keys, overwrite=False): with open(descfile, "w") as fp: for i in range(len(keys)//2): - k,v = keys[i*2:(i+1)*2] + k, v = keys[i*2:(i+1)*2] fp.write("{}: {}\n".format(k.capitalize(), v)) print("{} metadata key(s) written to {}".format(len(keys)//2, descfile)) From 72e58f0eef05e88caae18d55fc44d6ae45bd0f59 Mon Sep 17 00:00:00 2001 From: Simon Conseil Date: Wed, 3 Jan 2018 23:02:47 +0100 Subject: [PATCH 2/5] Add test for the build command --- sigal/__init__.py | 2 +- sigal/log.py | 15 +++++++++----- tests/test_cli.py | 50 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/sigal/__init__.py b/sigal/__init__.py index af754ff..6a14cf3 100644 --- a/sigal/__init__.py +++ b/sigal/__init__.py @@ -52,7 +52,7 @@ def main(): resize images, create thumbnails with some options, generate html pages. """ - pass + pass # pragma: no cover @main.command() diff --git a/sigal/log.py b/sigal/log.py index ac82406..41e229d 100644 --- a/sigal/log.py +++ b/sigal/log.py @@ -65,11 +65,16 @@ def init_logging(name, level=logging.INFO): logger = logging.getLogger(name) logger.setLevel(level) - if os.isatty(sys.stdout.fileno()) and not sys.platform.startswith('win'): - formatter = ColoredFormatter() - elif level == logging.DEBUG: - formatter = Formatter('%(levelname)s - %(message)s') - else: + try: + if os.isatty(sys.stdout.fileno()) and \ + not sys.platform.startswith('win'): + formatter = ColoredFormatter() + elif level == logging.DEBUG: + formatter = Formatter('%(levelname)s - %(message)s') + else: + formatter = Formatter('%(message)s') + except Exception: + # This fails when running tests with click (test_build) formatter = Formatter('%(message)s') handler = logging.StreamHandler() diff --git a/tests/test_cli.py b/tests/test_cli.py index 395519a..46dd871 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- +import logging import os from click.testing import CliRunner +from os.path import join -from sigal import init -from sigal import serve -from sigal import set_meta +from sigal import init, build, serve, set_meta + +TESTGAL = join(os.path.abspath(os.path.dirname(__file__)), 'sample') def test_init(tmpdir): @@ -22,6 +24,44 @@ def test_init(tmpdir): "keep it safe.\n") +def test_build(tmpdir): + runner = CliRunner() + config_file = str(tmpdir.join('sigal.conf.py')) + tmpdir.mkdir('pictures') + tmpdir = str(tmpdir) + cwd = os.getcwd() + + try: + result = runner.invoke(init, [config_file]) + assert result.exit_code == 0 + os.symlink(join(TESTGAL, 'pictures', 'dir2', 'exo20101028-b-full.jpg'), + join(tmpdir, 'pictures', 'exo20101028-b-full.jpg')) + + result = runner.invoke(build, ['-n', 1, '--debug']) + assert result.exit_code == 1 + + os.chdir(tmpdir) + + result = runner.invoke(build, ['foo', '-n', 1, '--debug']) + assert result.exit_code == 1 + + result = runner.invoke(build, ['pictures', 'pictures/out', + '-n', 1, '--debug']) + assert result.exit_code == 1 + + result = runner.invoke(build, ['pictures', 'build', + '-n', 1, '--debug']) + assert result.exit_code == 0 + assert os.path.isfile(join(tmpdir, 'build', 'thumbnails', + 'exo20101028-b-full.jpg')) + finally: + os.chdir(cwd) + # Reset logger + logger = logging.getLogger('sigal') + logger.handlers[:] = [] + logger.setLevel(logging.INFO) + + def test_serve(tmpdir): config_file = str(tmpdir.join('sigal.conf.py')) runner = CliRunner() @@ -34,6 +74,7 @@ def test_serve(tmpdir): result = runner.invoke(serve, ['-c', config_file]) assert result.exit_code == 1 + def test_set_meta(tmpdir): testdir = tmpdir.mkdir("test") @@ -53,7 +94,8 @@ def test_set_meta(tmpdir): result = runner.invoke(set_meta, [str(testdir), "title", "testing"]) assert result.exit_code == 2 - result = runner.invoke(set_meta, [str(testdir.join("non-existant.jpg")), "title", "testing"]) + result = runner.invoke(set_meta, [str(testdir.join("non-existant.jpg")), + "title", "testing"]) assert result.exit_code == 1 result = runner.invoke(set_meta, [str(testfile), "title", "testing"]) From 3fe48b05f31e53432379d38171ad446c02fdf1f2 Mon Sep 17 00:00:00 2001 From: Simon Conseil Date: Thu, 4 Jan 2018 00:15:47 +0100 Subject: [PATCH 3/5] more tests for plugins --- sigal/plugins/media_page.py | 3 --- sigal/plugins/nomedia.py | 12 ++++++++---- sigal/plugins/watermark.py | 19 ++++++++++--------- tests/test_cli.py | 34 +++++++++++++++++++++++++++++++++- tests/test_gallery.py | 3 ++- tests/test_nomedia_plugin.py | 27 --------------------------- tests/test_plugins.py | 31 +++++++++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 45 deletions(-) delete mode 100644 tests/test_nomedia_plugin.py create mode 100644 tests/test_plugins.py diff --git a/sigal/plugins/media_page.py b/sigal/plugins/media_page.py index 52d7c20..0152899 100644 --- a/sigal/plugins/media_page.py +++ b/sigal/plugins/media_page.py @@ -32,7 +32,6 @@ previous/next :class:`~sigal.gallery.Media` objects. """ import codecs -import logging import os from sigal import signals @@ -40,8 +39,6 @@ from sigal.writer import Writer from sigal.utils import url_from_path from sigal.pkgmeta import __url__ as sigal_link -logger = logging.getLogger(__name__) - class PageWriter(Writer): '''A writer for writing media pages, based on writer''' diff --git a/sigal/plugins/nomedia.py b/sigal/plugins/nomedia.py index e3774b9..48c7a16 100644 --- a/sigal/plugins/nomedia.py +++ b/sigal/plugins/nomedia.py @@ -60,18 +60,22 @@ def _remove_albums_with_subdirs(albums, keysToRemove, prefix=""): for keyToRemove in keysToRemove: for key in list(albums.keys()): if key.startswith(prefix + keyToRemove): - # subdirs' target directories have already been created, remove them first + # subdirs' target directories have already been created, + # remove them first try: album = albums[key] if album.medias: - os.rmdir(os.path.join(album.dst_path, album.settings['thumb_dir'])) + os.rmdir(os.path.join(album.dst_path, + album.settings['thumb_dir'])) if album.medias and album.settings['keep_orig']: - os.rmdir(os.path.join(album.dst_path, album.settings['orig_dir'])) + os.rmdir(os.path.join(album.dst_path, + album.settings['orig_dir'])) os.rmdir(album.dst_path) except OSError: - # directory was created and populated with images in a previous run => keep it + # directory was created and populated with images in a + # previous run => keep it pass # now remove the album from the surrounding album/gallery diff --git a/sigal/plugins/watermark.py b/sigal/plugins/watermark.py index 0478859..ad2ed08 100644 --- a/sigal/plugins/watermark.py +++ b/sigal/plugins/watermark.py @@ -27,21 +27,19 @@ Settings: - ``watermark``: path to the watermark image. - ``watermark_position``: the watermark position either 'scale' or 'tile' or - a 2-tuple giving the upper left corner, or - a 4-tuple defining the left, upper, right, and lower pixel coordinate, or - `None` (same as (0, 0)). - If a 4-tuple is given, the size of the pasted image must match the size of the region. + a 2-tuple giving the upper left corner, or + a 4-tuple defining the left, upper, right, and lower pixel coordinate, or + `None` (same as (0, 0)). + If a 4-tuple is given, the size of the pasted image must match the size of + the region. - ``watermark_opacity``: the watermark opacity (0.0 to 1.0). """ - import logging -from PIL import ImageDraw, Image, ImageEnhance +from PIL import Image, ImageEnhance from sigal import signals -logger = logging.getLogger(__name__) - def reduce_opacity(im, opacity): """Returns an image with reduced opacity.""" @@ -76,7 +74,8 @@ def watermark(im, mark, position, opacity=1): w = int(mark.size[0] * ratio) h = int(mark.size[1] * ratio) mark = mark.resize((w, h)) - layer.paste(mark, ((im.size[0] - w) / 2, (im.size[1] - h) / 2)) + layer.paste(mark, (int((im.size[0] - w) / 2), + int((im.size[1] - h) / 2))) else: layer.paste(mark, position) # composite the watermark with the layer @@ -84,6 +83,7 @@ def watermark(im, mark, position, opacity=1): def add_watermark(img, settings=None): + logger = logging.getLogger(__name__) logger.debug('Adding watermark to %r', img) mark = Image.open(settings['watermark']) position = settings.get('watermark_position', 'scale') @@ -92,6 +92,7 @@ def add_watermark(img, settings=None): def register(settings): + logger = logging.getLogger(__name__) if settings.get('watermark'): signals.img_resized.connect(add_watermark) else: diff --git a/tests/test_cli.py b/tests/test_cli.py index 46dd871..261aa52 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- +import blinker +import io import logging import os from click.testing import CliRunner from os.path import join -from sigal import init, build, serve, set_meta +from sigal import init, build, serve, set_meta, signals TESTGAL = join(os.path.abspath(os.path.dirname(__file__)), 'sample') @@ -34,6 +36,8 @@ def test_build(tmpdir): try: result = runner.invoke(init, [config_file]) assert result.exit_code == 0 + os.symlink(join(TESTGAL, 'watermark.png'), + join(tmpdir, 'watermark.png')) os.symlink(join(TESTGAL, 'pictures', 'dir2', 'exo20101028-b-full.jpg'), join(tmpdir, 'pictures', 'exo20101028-b-full.jpg')) @@ -49,6 +53,25 @@ def test_build(tmpdir): '-n', 1, '--debug']) assert result.exit_code == 1 + with io.open(config_file) as f: + text = f.read() + + text += """ +theme = 'colorbox' +plugins = ['sigal.plugins.adjust', 'sigal.plugins.copyright', + 'sigal.plugins.watermark', 'sigal.plugins.feeds', + 'sigal.plugins.media_page' 'sigal.plugins.nomedia', + 'sigal.plugins.extended_caching'] +copyright = u"© An example copyright message" +copyright_text_font = "foobar" +watermark = "watermark.png" +watermark_position = "scale" +watermark_opacity = 0.3 +""" + + with io.open(config_file, 'w') as f: + f.write(text) + result = runner.invoke(build, ['pictures', 'build', '-n', 1, '--debug']) assert result.exit_code == 0 @@ -60,6 +83,15 @@ def test_build(tmpdir): logger = logging.getLogger('sigal') logger.handlers[:] = [] logger.setLevel(logging.INFO) + # Reset plugins + for name in dir(signals): + if not name.startswith('_'): + try: + sig = getattr(signals, name) + if isinstance(sig, blinker.Signal): + sig.receivers.clear() + except Exception: + pass def test_serve(tmpdir): diff --git a/tests/test_gallery.py b/tests/test_gallery.py index 0e1647e..67019b1 100644 --- a/tests/test_gallery.py +++ b/tests/test_gallery.py @@ -225,7 +225,8 @@ def test_medias_sort(settings): settings['medias_sort_reverse'] = False a = Album('dir1/test2', settings, album['subdirs'], album['medias'], gal) a.sort_medias(settings['medias_sort_attr']) - assert [im.filename for im in a.images] == ['archlinux-kiss-1024x640.png', '21.jpg', '22.jpg'] + assert [im.filename for im in a.images] == [ + 'archlinux-kiss-1024x640.png', '21.jpg', '22.jpg'] def test_gallery(settings, tmpdir): diff --git a/tests/test_nomedia_plugin.py b/tests/test_nomedia_plugin.py deleted file mode 100644 index 0a76116..0000000 --- a/tests/test_nomedia_plugin.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding:utf-8 -*- - -import os - -from sigal.gallery import Gallery -from sigal import init_plugins - -CURRENT_DIR = os.path.dirname(__file__) - -def test_nomedia_plugin(settings, tmpdir): - - settings['destination'] = str(tmpdir) - if "plugins"in settings: - if not "sigal.plugins.nomedia" in settings["plugins"]: - settings['plugins'] += ["sigal.plugins.nomedia"] - else: - settings["plugins"] = ["sigal.plugins.nomedia"] - - init_plugins(settings) - gal = Gallery(settings) - gal.build() - - for path, dirs, files in os.walk(os.path.join(str(tmpdir), "nomedia")): - assert "ignore" not in path - - for file in files: - assert "ignore" not in file \ No newline at end of file diff --git a/tests/test_plugins.py b/tests/test_plugins.py new file mode 100644 index 0000000..d648ee8 --- /dev/null +++ b/tests/test_plugins.py @@ -0,0 +1,31 @@ +# -*- coding:utf-8 -*- + +import os + +from sigal.gallery import Gallery +from sigal import init_plugins + +CURRENT_DIR = os.path.dirname(__file__) + + +def test_plugins(settings, tmpdir): + + settings['destination'] = str(tmpdir) + if "sigal.plugins.nomedia" not in settings["plugins"]: + settings['plugins'] += ["sigal.plugins.nomedia"] + if "sigal.plugins.media_page" not in settings["plugins"]: + settings['plugins'] += ["sigal.plugins.media_page"] + + init_plugins(settings) + gal = Gallery(settings) + gal.build() + + out_html = os.path.join(settings['destination'], + 'dir2', 'exo20101028-b-full.jpg.html') + assert os.path.isfile(out_html) + + for path, dirs, files in os.walk(os.path.join(str(tmpdir), "nomedia")): + assert "ignore" not in path + + for file in files: + assert "ignore" not in file From cbfd9514f2664adb53c376abb6b9c809501f4c1e Mon Sep 17 00:00:00 2001 From: Simon Conseil Date: Thu, 4 Jan 2018 00:46:34 +0100 Subject: [PATCH 4/5] pep8 --- sigal/plugins/upload_s3.py | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/sigal/plugins/upload_s3.py b/sigal/plugins/upload_s3.py index 0594ab0..cbe196f 100644 --- a/sigal/plugins/upload_s3.py +++ b/sigal/plugins/upload_s3.py @@ -2,11 +2,11 @@ """Plugin to upload generated files to Amazon S3. -This plugin requires boto_. All generated files are uploaded to a specified S3 bucket. -When using this plugin you have to make sure that the bucket already exists and the -you have access to the S3 bucket. The access credentials are managed by boto_ and -can be given as environment variables, configuration files etc. More information -can be found on the boto_ documentation. +This plugin requires boto_. All generated files are uploaded to a specified S3 +bucket. When using this plugin you have to make sure that the bucket already +exists and the you have access to the S3 bucket. The access credentials are +managed by boto_ and can be given as environment variables, configuration files +etc. More information can be found on the boto_ documentation. .. _boto: https://pypi.python.org/pypi/boto @@ -14,23 +14,25 @@ Settings (all settings are wrapped in ``upload_s3_options`` dict): - ``bucket``: The to-be-used bucket for uploading. - ``policy``: Specifying access control to the uploaded files. Possible values: - private, public-read, public-read-write, authenticated-read -- ``overwrite``: Boolean indicating if all files should be uploaded and overwritten - or if already uploaded files should be skipped. -- ``max_age``: Optional, Integer indicating the number of seconds that the cache - control should be set by default + private, public-read, public-read-write, authenticated-read +- ``overwrite``: Boolean indicating if all files should be uploaded and + overwritten or if already uploaded files should be skipped. +- ``max_age``: Optional, Integer indicating the number of seconds that the + cache control should be set by default - ``media_max_age``: Optional, Integer indicates the number of seconds that - cache control hould be set for media files + cache control hould be set for media files """ +import boto import logging import os -from sigal import signals -import boto + from boto.s3.key import Key from click import progressbar +from sigal import signals + logger = logging.getLogger(__name__) @@ -40,9 +42,9 @@ def upload_s3(gallery, settings=None): # Get local files for root, dirs, files in os.walk(gallery.settings['destination']): for f in files: - path = os.path.join(root[len(gallery.settings['destination'])+1:], f) + path = os.path.join(root[len(gallery.settings['destination']) + 1:], f) size = os.path.getsize(os.path.join(root, f)) - upload_files += [ (path, size) ] + upload_files += [(path, size)] # Connect to specified bucket conn = boto.connect_s3() @@ -54,12 +56,12 @@ def upload_s3(gallery, settings=None): if gallery.settings['upload_s3_options']['overwrite'] == False: # Check if file was uploaded before key = bucket.get_key(f) - if key != None and key.size == size: - cache_metadata = generate_cache_metadata(gallery,f) + if key is not None and key.size == size: + cache_metadata = generate_cache_metadata(gallery, f) if key.get_metadata('Cache-Control') != cache_metadata: key.set_remote_metadata({ - 'Cache-Control':cache_metadata},{},True); + 'Cache-Control': cache_metadata}, {}, True) logger.debug("Skipping file %s" % (f)) else: upload_file(gallery, bucket, f) @@ -67,12 +69,13 @@ def upload_s3(gallery, settings=None): # File is not available on S3 yet upload_file(gallery, bucket, f) + def generate_cache_metadata(gallery, f): filename, file_extension = os.path.splitext(f) proposed_cache_control = None if 'media_max_age' in gallery.settings['upload_s3_options'] and \ - file_extension in ['.jpg','.png','.webm','.mp4']: + file_extension in ['.jpg', '.png', '.webm', '.mp4']: proposed_cache_control = "max-age=%s" % \ gallery.settings['upload_s3_options']['media_max_age'] elif 'max_age' in gallery.settings['upload_s3_options']: @@ -80,6 +83,7 @@ def generate_cache_metadata(gallery, f): gallery.settings['upload_s3_options']['max_age'] return proposed_cache_control + def upload_file(gallery, bucket, f): logger.debug("Uploading file %s" % (f)) @@ -92,7 +96,8 @@ def upload_file(gallery, bucket, f): key.set_contents_from_filename( os.path.join(gallery.settings['destination'], f), - policy = gallery.settings['upload_s3_options']['policy']) + policy=gallery.settings['upload_s3_options']['policy']) + def register(settings): if settings.get('upload_s3_options'): From 5a8046caa14ad0a73b2eb0dbdcd41e61aa174307 Mon Sep 17 00:00:00 2001 From: Simon Conseil Date: Fri, 5 Jan 2018 00:32:13 +0100 Subject: [PATCH 5/5] Fix py2 compat --- tests/test_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 261aa52..2fa1b32 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -62,7 +62,7 @@ plugins = ['sigal.plugins.adjust', 'sigal.plugins.copyright', 'sigal.plugins.watermark', 'sigal.plugins.feeds', 'sigal.plugins.media_page' 'sigal.plugins.nomedia', 'sigal.plugins.extended_caching'] -copyright = u"© An example copyright message" +copyright = "An example copyright message" copyright_text_font = "foobar" watermark = "watermark.png" watermark_position = "scale"