__title__ = 'fobi.helpers'
__author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
__copyright__ = 'Copyright (c) 2014 Artur Barseghyan'
__license__ = 'GPL 2.0/LGPL 2.1'
__all__ = (
'do_slugify', 'lists_overlap', 'iterable_to_dict', 'map_field_name_to_label',
'clean_dict', 'two_dicts_to_string', 'empty_string', 'ensure_unique_filename',
'handle_uploaded_file', 'delete_file', 'clone_file', 'get_registered_models',
'admin_change_url', 'uniquify_sequence', 'safe_text',
)
import os
import glob
import logging
import uuid
import shutil
from six import text_type, PY3
from django.conf import settings
from django.core.urlresolvers import reverse
from django.core.files.base import File
from django.contrib.contenttypes.models import ContentType
from django.db.utils import DatabaseError
from django.utils.encoding import force_text
from autoslug.settings import slugify
logger = logging.getLogger(__name__)
# ******************************************************************************
# ******************************************************************************
# ********************************** General ***********************************
# ******************************************************************************
# ******************************************************************************
do_slugify = lambda s: slugify(s.lower()).lower()
[docs]def lists_overlap(sub, main):
for i in sub:
if i in main:
return True
return False
[docs]def iterable_to_dict(items, key_attr_name):
"""
Converts iterable of certain objects to dict.
:param iterable items:
:param string key_attr_name: Attribute to use as a dictionary key.
:return dict:
"""
items_dict = {}
for item in items:
items_dict.update({getattr(item, key_attr_name): item})
return items_dict
[docs]def map_field_name_to_label(form):
"""
Takes a form and creates label to field name map.
:param django.forms.Form form: Instance of ``django.forms.Form``.
:param list keys_to_remove:
:return dict:
"""
return dict([(field_name, field.label) for (field_name, field) in form.base_fields.items()])
[docs]def clean_dict(source, keys=[], values=[]):
"""
Removes given keys and values from dictionary.
:param dict source:
:param iterable keys:
:param iterable values:
:return dict:
"""
d = {}
for key, value in source.items():
if (not key in keys) and (not value in values):
d[key] = value
return d
[docs]def two_dicts_to_string(headers, data, html_element='p'):
"""
Takes two dictionaries, assuming one contains a mapping keys to titles
and another keys to data. Joins as string and returns wrapped into
HTML "p" tag.
"""
formatted_data = [(value, data.get(key, '')) for key, value in list(headers.items())]
return "".join(["<{0}>{1}: {2}</{3}>".format(html_element, key, value, html_element) \
for key, value in formatted_data])
empty_string = text_type('')
[docs]def uniquify_sequence(sequence):
"""
Makes sure items in the given sequence are unique, having the original order preserved.
:param iterable sequence:
:return list:
"""
seen = set()
seen_add = seen.add
return [x for x in sequence if x not in seen and not seen_add(x)]
def get_ignorable_form_values():
"""
Gets an iterable of form values to ignore.
:return iterable:
"""
return [None, empty_string,]
[docs]def safe_text(text):
"""
Safe text (encode).
:return str:
"""
if PY3:
return force_text(text, encoding='utf-8')
else:
return force_text(text, encoding='utf-8').encode('utf-8')
# ******************************************************************************
# ******************************************************************************
# ****************************** File helpers **********************************
# ******************************************************************************
# ******************************************************************************
[docs]def ensure_unique_filename(destination):
"""
Makes sure filenames are never overwritten.
:param string destination:
:return string:
"""
if os.path.exists(destination):
filename, extension = os.path.splitext(destination)
return "{0}_{1}{2}".format(filename, uuid.uuid4(), extension)
else:
return destination
[docs]def handle_uploaded_file(upload_dir, image_file):
"""
:param django.core.files.uploadedfile.InMemoryUploadedFile image_file:
:return string: Path to the image (relative).
"""
upload_dir_absolute_path = os.path.join(settings.MEDIA_ROOT, upload_dir)
if isinstance(image_file, File):
destination_path = ensure_unique_filename(os.path.join(upload_dir_absolute_path, image_file.name))
image_filename = image_file.name
with open(destination_path, 'wb+') as destination:
image_filename = os.path.basename(destination.name)
for chunk in image_file.chunks():
destination.write(chunk)
return os.path.join(upload_dir, image_filename)
return image_file
[docs]def delete_file(image_file):
"""
Delete file from disc.
"""
try:
# Delete the main file.
file_path = os.path.join(settings.MEDIA_ROOT, image_file)
os.remove(file_path)
# Delete the sized version of it.
files = glob.glob("{0}*".format(file_path))
for f in files:
try:
os.remove(f)
except Exception as e:
logger.debug(str(e))
# If all goes well...
return True
except Exception as e:
logger.debug(str(e))
return False
[docs]def clone_file(upload_dir, source_filename, relative_path=True):
"""
Clones the file.
:param string source_filename: Source filename.
:return string: Filename of the cloned file.
"""
if source_filename.startswith(upload_dir):
source_filename = os.path.join(settings.MEDIA_ROOT, source_filename)
destination_filename = ensure_unique_filename(source_filename)
try:
shutil.copyfile(source_filename, destination_filename)
if relative_path:
destination_filename = destination_filename.replace(settings.MEDIA_ROOT, '')
if destination_filename.startswith('/'):
destination_filename = destination_filename[1:]
return destination_filename
except Exception as e:
logger.debug(str(e))
# ******************************************************************************
# ******************************************************************************
# ****************************** Model helpers *********************************
# ******************************************************************************
# ******************************************************************************
[docs]def get_registered_models(ignore=[]):
"""
Gets registered models as list.
:param iterable ignore: Ignore the following content types (should
be in ``app_label.model`` format (example ``auth.User``).
:return list:
"""
registered_models = []
try:
content_types = ContentType._default_manager.all()
for content_type in content_types:
#model = content_type.model_class()
content_type_id = "{0}.{1}".format(content_type.app_label, content_type.model)
if not content_type_id in ignore:
registered_models.append((content_type_id, content_type.name))
except DatabaseError as e:
logger.debug(str(e))
return registered_models
# ******************************************************************************
# ******************************************************************************
# ****************************** Admin helpers *********************************
# ******************************************************************************
# ******************************************************************************
[docs]def admin_change_url(app_label, module_name, object_id, extra_path='', url_title=None):
"""
Gets an admin change URL for the object given.
:param str app_label:
:param str module_name:
:param int object_id:
:param str extra_path:
:param str url_title: If given, an HTML a tag is returned with `url_title` as the tag title. If left to None
just the URL string is returned.
:return str:
"""
try:
url = reverse('admin:%s_%s_change' %(app_label, module_name), args=[object_id]) + extra_path
if url_title:
return u'<a href="%s">%s</a>' %(url, url_title)
else:
return url
except:
return None
# ******************************************************************************
# ******************************************************************************
# ****************************** Fobi data helpers *****************************
# ******************************************************************************
# ******************************************************************************
def update_plugin_data(entry, request=None):
"""
Update plugin data of a given entry.
"""
if entry:
plugin = entry.get_plugin(request=request)
logger.debug(plugin)
if plugin:
return plugin._update_plugin_data(entry)