Commits

Artur Barseghyan committed 71f2786 Draft

initial work on python 3 compatibility; resome factoring

  • Participants
  • Parent commits 9543cc0

Comments (0)

Files changed (20)

 build/
 dist/
 src/eximagination.egg-info
-
+src/eximagination/tmp/
 ^build/
 ^dist/
 ^src/eximagination.egg-info
+^src/eximagination/tmp/
+=======================================
+eximagination
+=======================================
+A Django template tag library which allows downloading of external images right from the template and save it
+into a desired context variable along with `width` and `height` of the image fetched. Caches the fetched images
+locally.
+
+You could, for example, use this app to solve the problems with displaying of a mixed content (assets loaded
+from HTTP and HTTPS sources).
+
+Installation
+=======================================
+1. Install eximagination
+
+Latest stable version on PyPI:
+
+    $ pip install eximagination
+
+Latest stable version from bitbucket:
+
+    $ pip install -e hg+http://bitbucket.org/barseghyanartur/eximagination@stable#egg=eximagination
+
+2. Add 'eximagination' to `INSTALLED_APPS`
+
+>>> INSTALLED_APPS = (
+>>>     # ...
+>>>     'eximagination',
+>>>     # ...
+>>> )
+
+3. Configure
+
+By default, eximagination expects your files to be stored in '/media/external_images' directory. If location varies,
+redefine the directories in your Django settings, make sure the path is writable and that www-data (or whatever is
+applicable) has rights to write into it.
+
+>>> # Example settings.py
+>>> import os
+>>> PROJECT_DIR = lambda s: os.path.abspath(os.path.join(os.path.dirname(__file__), s).replace('\\','/'))
+>>> EXIMAGINATION_MEDIA_ROOT = PROJECT_DIR('media/external_images/')
+>>> EXIMAGINATION_MEDIA_URL = '/media/external_images'
+>>> EXIMAGINATION_MEDIA_RELATIVE_ROOT = 'external_images/'
+>>> EXIMAGINATION_EXPIRATION_INTERVAL = 2592000 # After 30 days we re-fetch the file anyway.
+
+Usage example (in a Django template)
+=======================================
+See the `example` directory in https://bitbucket.org/barseghyanartur/eximagination/src for working code example.
+
+{% load eximaginate %}
+
+<img src="{{ MEDIA_URL }}{% eximaginate 'http://www.google.com/intl/en/images/logo.gif' %}">
+
+or
+
+{% load eximaginate thumbnail %}
+
+{% eximaginate 'http://www.google.com/intl/en/images/logo.gif' as original %}
+
+<img src="{% thumbnail original 100x100 %}">
+
+In both cases there are two additional context variables added:
+
+    `ei_width` - Width of the image
+
+    `ei_height` - Height of the image
+
+License
+=======================================
+GPL 2.0/LGPL 2.1
+
+Support
+=======================================
+For any issues contact me at the e-mail given in the `Author` section or open an issue on bitbucket/github.
+
+Author
+=======================================
+Artur Barseghyan <artur.barseghyan@gmail.com>
+TODOS
+==========================
+Based on MoSCoW principle
+
+Must haves
+--------------------------
+
+Should haves
+--------------------------
+- Add redis for caching of file lists (avoid call to file system). It should be possible to switch that feature
+  on and off.
+
+- Add a management command to update all existing files.
+
+- Add an expiration time (after which the file shall be downloaded again).
+
+Could haves
+--------------------------
+
+Would haves
+--------------------------

File builddocs.sh

+./uninstall.sh
+reset
+./install.sh
+reset
+sphinx-build -n -a -b html docs builddocs
+cd builddocs && zip -r ../builddocs.zip . -x ".*" && cd ..

File example/example/templates/eximagination/test.html

 {% extends "base.html" %}
-{% load eximaginate thumbnail %}
+{% load eximaginate %}{# thumbnail #}
 
 {% block page-title %}Test{% endblock page-title %}
 
 <h2>Test 2</h2>
 <p>
     {% eximaginate 'http://www.google.com/intl/en/images/logo.gif' as original %}
-    <img src="{% thumbnail original 100x100 %}" alt="test 2 image"/>
+    <img src="{{ original }}" alt="test 2 image"/>
+    {#<img src="{% thumbnail original 100x100 %}" alt="test 2 image"/>#}
 </p>
 <p><small>Original image width: {{ ei_width }}</small></p>
 <p><small>Original image height: {{ ei_height }}</small></p>

File example/requirements.txt

-Django==1.5.1
-Jinja2==2.7
-MarkupSafe==0.18
+Django==1.5.4
 Pillow==2.1.0
-Pygments==1.6
-Sphinx==1.2b1
-argparse==1.2.1
 django-debug-toolbar==0.9.4
-docutils==0.10
-eximagination==0.5
-ipdb==0.7
-ipython==0.13.2
-sorl-thumbnail==3.2.5
-wsgiref==0.1.2
+#-e hg+http://bitbucket.org/barseghyanartur/eximagination@stable#egg=eximagination
+reset
+python setup.py install

File readme.rst

-=======================================
-eximagination
-=======================================
-
-Description
-=======================================
-A Django template tag library which allows downloading of external images right from the template and save it into a
-desired context variable along with `width` and `height` of the image fetched. Caches the fetched images locally.
-You could, for example, use this app to solve the problems with displaying of a mixed content (assets loaded from HTTP and HTTPS
-sources).
-
-Installation
-=======================================
-1. Install eximagination
-
-Latest stable version on PyPI:
-
-    $ pip install eximagination
-
-Latest development version from source:
-
-    $ pip install -e hg+http://bitbucket.org/barseghyanartur/eximagination@dev#egg=eximagination
-
-2. Add 'eximagination' to `INSTALLED_APPS`
-
->>> INSTALLED_APPS = (
->>>     # ...
->>>     'eximagination',
->>>     # ...
->>> )
-
-3. Configure
-
-By default, eximagination expects your files to be stored in '/media/external_images' directory. If location varies,
-redefine the directories in your Django settings, make sure the path is writable and that www-data (or whatever is
-applicable) has rights to write into it.
-
->>> # Example settings.py
->>> import os
->>> PROJECT_DIR = lambda s: os.path.abspath(os.path.join(os.path.dirname(__file__), s).replace('\\','/'))
->>> EXIMAGINATION_MEDIA_ROOT = PROJECT_DIR('media/external_images/')
->>> EXIMAGINATION_MEDIA_URL = '/media/external_images'
->>> EXIMAGINATION_MEDIA_RELATIVE_ROOT = 'external_images/'
->>> EXIMAGINATION_EXPIRATION_INTERVAL = 2592000 # After 30 days we re-fetch the file anyway.
-
-Usage example (in a Django template)
-=======================================
-See the `example` directory in https://bitbucket.org/barseghyanartur/eximagination/src for working code example.
-
-{% load eximaginate %}
-
-<img src="{{ MEDIA_URL }}{% eximaginate 'http://www.google.com/intl/en/images/logo.gif' %}">
-
-or
-
-{% load eximaginate thumbnail %}
-
-{% eximaginate 'http://www.google.com/intl/en/images/logo.gif' as original %}
-
-<img src="{% thumbnail original 100x100 %}">
-
-In both cases there are two additional context variables added:
-
-    `ei_width` - Width of the image
-
-    `ei_height` - Height of the image
-
-License
-=======================================
-GPL 2.0/LGPL 2.1
-
-Support
-=======================================
-For any issues contact me at the e-mail given in the `Author` section or open an issue on bitbucket/github.
-
-Author
-=======================================
-Artur Barseghyan <artur.barseghyan@gmail.com>
     classifiers = [
         "Framework :: Django",
         "Programming Language :: Python",
+        "Programming Language :: Python :: 2.6",
+        "Programming Language :: Python :: 2.7",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.3",
+        "Development Status :: 4 - Beta",
         "Environment :: Web Environment",
-        'Intended Audience :: Developers',
+        "Intended Audience :: Developers",
         'Operating System :: OS Independent',
     ],
     keywords = 'eximagination, django, external images, app, python',
     package_dir = {'':'src'},
     packages = find_packages(where='./src'),
     license = 'GPL 2.0/LGPL 2.1',
+    install_requires = [
+        'six==1.4.1',
+        'Pillow==2.2.1'
+    ]
 )

File src/eximagination/conf.py

 __title__ = 'eximagination.conf'
-__version__ = '0.6'
-__build__ = 0x000006
+__version__ = '0.7'
+__build__ = 0x000007
 __author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
 __all__ = ('get_setting',)
 

File src/eximagination/defaults.py

 __title__ = 'eximagination.defaults'
-__version__ = '0.6'
-__build__ = 0x000006
+__version__ = '0.7'
+__build__ = 0x000007
 __author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
 __all__ = ('MEDIA_ROOT', 'MEDIA_URL', 'MEDIA_RELATIVE_ROOT', 'EXPIRATION_INTERVAL', 'DEBUG')
 

File src/eximagination/settings.py

 __title__ = 'eximagination.settings'
-__version__ = '0.6'
-__build__ = 0x000006
+__version__ = '0.7'
+__build__ = 0x000007
 __author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
 __all__ = ('MEDIA_ROOT', 'MEDIA_URL', 'MEDIA_RELATIVE_ROOT', 'EXPIRATION_INTERVAL', 'DEBUG')
 

File src/eximagination/templatetags/eximaginate.py

 __title__ = 'eximagination.templatetags.eximaginate'
-__version__ = '0.6'
-__build__ = 0x000006
+__version__ = '0.7'
+__build__ = 0x000007
 __author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
 __all__ = ('eximaginate',)
 
 from django import template
 
-from eximagination.utils import _obtain_image
-from eximagination.settings import MEDIA_ROOT, MEDIA_RELATIVE_ROOT
+from eximagination.utils import obtain_image
+from eximagination.settings import MEDIA_ROOT, MEDIA_RELATIVE_ROOT, EXPIRATION_INTERVAL, DEBUG
 
 register = template.Library()
 
     :example:
     {% eximaginate photo as image %}
     {{ image }}
-    :note: Eximagination will automatically add `ei_width` and `ei_height` variables to the content -
+    :note: Eximagination will automatically add ``ei_width`` and ``ei_height`` variables to the content -
         those are the original width and height values of the obtained image.
     """
     def __init__(self, source_var, force_update, context_name=None):
         # Note that this isn't a global constant because we need to change the
         # value for tests.
         try:
-            file_data = _obtain_image(image_source=self.source_var.resolve(context),
-                                      save_to=MEDIA_ROOT,
-                                      media_url=MEDIA_RELATIVE_ROOT,
-                                      force_update=self.force_update)
+            file_data = obtain_image(
+                image_source = self.source_var.resolve(context),
+                save_to = MEDIA_ROOT,
+                media_url = MEDIA_RELATIVE_ROOT,
+                force_update = self.force_update,
+                expiration_interval = EXPIRATION_INTERVAL,
+                debug = DEBUG
+                )
             filename = file_data[0]
             context['ei_width'] = file_data[1] # Original width of the obtained image
             context['ei_height'] = file_data[2] # Original height of the obtained image
     # Check to see if we're setting to a context variable.
 
     if len(arguments) < 1:
-        raise template.TemplateSyntaxError, "%r tag requires at least one argument" % token.contents.split()[0]
+        raise template.TemplateSyntaxError("{0} tag requires at least one argument".format(token.contents.split()[0]))
 
     # Get arguments
     if 4 == len(arguments):
         force_update = False # At the moment force_update is not implemented
         context_name = None
     else:
-        raise template.TemplateSyntaxError, "%r wrong number arguments" % token.contents.split()[0]
+        raise template.TemplateSyntaxError("{0} wrong number arguments".format(token.contents.split()[0]))
 
     # If the size argument was a correct static format, wrap it in quotes so
     # that it is compiled correctly.

File src/eximagination/tests.py

+from __future__ import print_function
+
+__title__ = 'eximagination.utils'
+__version__ = '0.7'
+__build__ = 0x000007
+__author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
+
+import unittest
+import os
+PROJECT_DIR = lambda base : os.path.join(os.path.dirname(__file__), base).replace('\\','/')
+
+from eximagination.utils import obtain_image
+
+PRINT_INFO = True
+
+def print_info(func):
+    """
+    Prints some useful info.
+    """
+    if not PRINT_INFO:
+        return func
+
+    def inner(self, *args, **kwargs):
+        result = func(self, *args, **kwargs)
+
+        print('\n\n%s' % func.__name__)
+        print('============================')
+        if func.__doc__:
+            print('""" %s """' % func.__doc__.strip())
+        print('----------------------------')
+        if result is not None:
+            print(result)
+        print('\n++++++++++++++++++++++++++++')
+
+        return result
+    return inner
+
+class EximaginationUtilsTest(unittest.TestCase):
+    """
+    Tests of ``simple_timer.Timer`` class.
+    """
+    def setUp(self):
+        self.image_url = 'http://www.google.com/intl/en/images/logo.gif'
+        self.force_update = False
+        
+        self.MEDIA_ROOT = PROJECT_DIR('tmp') # Where eximagination cached images will be stored
+        self.MEDIA_URL = '/tmp/' # Media URL for stored images
+        self.MEDIA_RELATIVE_ROOT = 'tmp/' # Relative root for images
+        self.EXPIRATION_INTERVAL = 2592000 # After 30 days we re-fetch the file anyway.
+        self.DEBUG = True
+
+        try:
+            os.stat(self.MEDIA_ROOT)
+        except:
+            os.mkdir(self.MEDIA_ROOT)
+
+    @print_info
+    def test_01_obtain_image(self):
+        """
+        Test obtain image.
+        """
+        #import ipdb; ipdb.set_trace()
+        file_data = obtain_image(
+            image_source = self.image_url,
+            save_to = self.MEDIA_ROOT,
+            media_url = self.MEDIA_RELATIVE_ROOT,
+            force_update = self.force_update,
+            expiration_interval = self.EXPIRATION_INTERVAL,
+            debug = self.DEBUG
+            )
+
+        try:
+            filename = file_data[0]
+            ei_width = file_data[1] # Original width of the obtained image
+            ei_height = file_data[2] # Original height of the obtained image
+        except Exception as e:
+            print(file_data)
+            print(e)
+            filename = None
+            ei_width = None
+            ei_height = None
+
+        res = {
+            'filename': filename,
+            'ei_width': ei_width,
+            'ei_height': ei_height
+        }
+
+        self.assertTrue(filename is not None)
+        self.assertTrue(ei_width is not None)
+        self.assertTrue(ei_height is not None)
+
+        return res
+
+
+if __name__ == "__main__":
+    # Tests
+    unittest.main()

File src/eximagination/utils.py

 __title__ = 'eximagination.utils'
-__version__ = '0.6'
-__build__ = 0x000006
+__version__ = '0.7'
+__build__ = 0x000007
 __author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
-__all__ = ('_obtain_image',)
+__all__ = ('obtain_image',)
 
-import urllib2
 import os
 import hashlib
-from PIL import Image
-import StringIO
 import glob
 import time
+from PIL import Image
 
-from eximagination.settings import EXPIRATION_INTERVAL, DEBUG
+from six import PY2, PY3
+from six.moves.urllib.request import build_opener
+from six import StringIO
+#try:
+#    import StringIO
+#except ImportError as e:
+#    from cStringIO import StringIO
 
-def _obtain_image(image_source='', save_to='', media_url='', force_update=False):
+def obtain_image(image_source='', save_to='', media_url='', force_update=False, expiration_interval=None, debug=False):
     """
     Gets an image from absolute url and saves it locally. Checks wheither image already exists in local directoru
     and only if not - tries to download it and saves it. Validates validity of the image (relying on PIL Image
     class validation).
 
-    :param image_source: str
-    :param save_to: str
-    :param media_url: str
-    :param force_update: bool
+    :param str image_source:
+    :param str save_to:
+    :param str media_url:
+    :param bool force_update:
+    :param int expiration_interval: Expiration interval in seconds.
+    :param bool debug:
     :return list: (relative_url_of_the_image, original_image_width, original_image_height)
     """
     # First we check if any image with such name (without extention) exists in our local external images directory.
         # Expiration interval check.
         full_path = os.path.join(save_to, filename)
         last_modified = os.path.getmtime(full_path)
-        if time.time() - last_modified > EXPIRATION_INTERVAL:
+        if time.time() - last_modified > expiration_interval:
             expired = True
 
         if not expired:
             im = Image.open(full_path) # Feed the image to PIL to get width and height
             return (os.path.join(media_url, filename), im.size[0], im.size[1])
-    except Exception, e:
+    except Exception as e:
         pass
 
     # If nothing was found in local directory (or perhaps file expired) - we try to load it and save it.
     try:
         # Loading the file of unknown type into memory. We don't save the image locally before it's validated.
-        opener = urllib2.build_opener()
+        opener = build_opener()
         page = opener.open(image_source)
         external_image = page.read()
 
         # Loading into PIL image in order to check if image is a proper image as well as to detect its' extention.
         # This is probably the best way to validate the image and get its' extention, since PIL Image throws an
         # exception when trying to load not a proper image.
-        im = Image.open(StringIO.StringIO(external_image))
+        #try:
+        im = Image.open(StringIO(external_image))
+        #except Exception as e:
+        #    import pdb; pdb.set_trace()
 
         # This is our filename
         filename = hashlib.md5(image_source).hexdigest() + '.' + im.format.lower()
         fout.write(external_image)
         fout.close()
         return (os.path.join(media_url, filename), im.size[0], im.size[1])
-    except Exception, e:
-        if DEBUG:
+    except Exception as e:
+        if debug:
             raise Exception("Wrong image type or can load the image")
         else:
             return ''
+./uninstall.sh
+reset
+./install.sh
+reset
+python src/eximagination/tests.py

File todos.rst

-TODOS
-==========================
-Based on MoSCoW principle
-
-Must haves
---------------------------
-
-Should haves
---------------------------
-- Add redis for caching of file lists (avoid call to file system). It should be possible to switch that feature
-  on and off.
-
-- Add a management command to update all existing files.
-
-- Add an expiration time (after which the file shall be downloaded again).
-
-Could haves
---------------------------
-
-Would haves
---------------------------
+[tox]
+envlist = py26,py27,py33
+
+[testenv:py26]
+changedir=src/eximagination/
+deps=unittest2
+commands=unit2 discover []
+
+[testenv:py27]
+changedir=src/eximagination/
+deps=unittest2
+commands=unit2 discover []
+
+[testenv:py33]
+basepython=/opt/python3.3/bin/python3.3
+changedir=src/eximagination/
+commands=
+    {envpython} tests.py

File uninstall.sh

+reset
+pip uninstall eximagination -y
+rm build -rf
+rm dist -rf
+rm builddocs.zip
+rm src/eximagination.egg-info -rf
+rm src/eximagination/tmp/ -rf