Commits

Antoni Aloy committed 0e02407 Draft

first commit

Comments (0)

Files changed (12)

+#use glob syntax.
+syntax: glob
+properties.py
+*.pyc
+*~
+*.swp
+*.geany
+
+syntax: regexp
+
+.*thumb\.[jpg|png|gif]
+

apsl_lib/__init__.py

Empty file added.

apsl_lib/context_processors/__init__.py

+#!/usr/bin/env python
+#-*- coding: UTF-8 -*-
+
+from django.conf import settings
+
+
+def devel(request):
+    """
+    Lets you to define a DEVEL settins on your project
+    """
+    return {'DEVEL': getattr(settins, 'DEVEL', False}
+
+
+def google(rquest):
+    """Allows you to define your GOOGLE_CODE for analytics"""
+    try:
+        return {'GOOGLE_CODE':settings.GOOGLE_CODE}
+    except AttributeError:
+        return {'GOOGLE_CODE': ''}
+

apsl_lib/decorators.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+class Lazy(object):
+    def __init__(self, calculate_function):
+        self._calculate = calculate_function
+
+    def __get__(self, obj, _=None):
+        if obj is None:
+            return self
+        value = self._calculate(obj)
+        setattr(obj, self._calculate.func_name, value)
+        return value

apsl_lib/interval.py

+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+from datetime import datetime, timedelta
+
+
+def datetime_iterator(from_date=datetime.now(), to_date=None):
+    """
+    Returns a list of dates from the start date (from_date)
+    to the end data (to_date)
+    """
+
+    while to_date is None or from_date <= to_date:
+        yield from_date
+        from_date = from_date + timedelta(days=1)
+    return
+
+
+def overlaps_in_range(lista, inicio, fin, f=lambda x: x):
+    """
+    Returns true if interval given by (inicio, fin) overlaps with
+    any interval specified in lista
+
+    f must be a function thath would return a date interval from
+    each element of the list.
+    """
+
+    for x in lista:
+        r = f(x)
+        if not ((r[1] < inicio) or (r[0] > fin)):
+            return True
+    return False
+
+
+def inside(mayor, menor):
+    """
+    Returns true if intervan menor is inside interval mayor or both
+    are equal.
+
+    inside ( (2,5), (3,4)) -> True
+    inside ( (2,5), (4, 6) -> False
+
+    """
+
+    return (mayor[0] <= menor[0]) and (mayor[1] >= menor[1])

apsl_lib/manager.py

+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+from types import ClassType
+from django.db.models.manager import Manager
+from django.db.models.query import QuerySet
+
+"""
+from datetime import datetime
+from django.db import models
+from django.contrib.auth.models import User
+
+class AuthorMixin(object):
+    def by_author(self, user):
+        return self.filter(user=user)
+
+class PublishedMixin(object):
+    def published(self):
+        return self.filter(published__lte=datetime.now())
+
+def unpublished(self):
+    return self.filter(published__gte=datetime.now())
+
+class CustomManager(Manager):
+    def get_query_set(self):
+        return super(CustomManager, self).get_query_set().order_by('-published')
+
+class Post(models.Model):
+    user = models.ForeignKey(User)
+    published = models.DateTimeField()
+
+    objects = manager_from(AuthorMixin, PublishedMixin, unpublished,
+                              manager_cls=CustomManager)
+
+
+print Post.objects.by_author(user=12).unpublished().query
+
+
+"""
+
+
+def manager_from(*mixins, **kwds):
+    '''
+    Returns a Manager instance with extra methods, also available and
+    chainable on generated querysets.
+
+    :param mixins: Each ``mixin`` can be either a class or a function. The
+        generated manager and associated queryset subclasses extend the mixin
+        classes and include the mixin functions (as methods).
+
+    :keyword queryset_cls: The base queryset class to extend from
+        (``django.db.models.query.QuerySet`` by default).
+
+    :keyword manager_cls: The base manager class to extend from
+        (``django.db.models.manager.Manager`` by default).
+    '''
+    # collect separately the mixin classes and methods
+    bases = [kwds.get('queryset_cls', QuerySet)]
+    methods = {}
+    for mixin in mixins:
+        if isinstance(mixin, (ClassType, type)):
+            bases.append(mixin)
+        else:
+            try:
+                methods[mixin.__name__] = mixin
+            except AttributeError:
+                raise TypeError('Mixin must be class or function, not %s' %
+                                mixin.__class__)
+    # create the QuerySet subclass
+    id = hash(mixins + tuple(kwds.iteritems()))
+    new_queryset_cls = type('Queryset_%d' % id, tuple(bases), methods)
+    # create the Manager subclass
+    bases[0] = manager_cls = kwds.get('manager_cls', Manager)
+    new_manager_cls = type('Manager_%d' % id, tuple(bases), methods)
+    # and finally override new manager's get_query_set
+    super_get_query_set = manager_cls.get_query_set
+
+    def get_query_set(self):
+        # first honor the super manager's get_query_set
+        qs = super_get_query_set(self)
+        # and then try to bless the returned queryset by reassigning it to the
+        # newly created Queryset class, though this may not be feasible
+        if not issubclass(new_queryset_cls, qs.__class__):
+            raise TypeError('QuerySet subclass conflict: cannot determine a '
+                            'unique class for queryset instance')
+        qs.__class__ = new_queryset_cls
+        return qs
+    new_manager_cls.get_query_set = get_query_set
+    return new_manager_cls()

apsl_lib/models.py

Empty file added.

apsl_lib/templatetags/__init__.py

Empty file added.

apsl_lib/templatetags/apsl_tags.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from django.template import Library, Node, TemplateSyntaxError
+from django.template.defaultfilters import stringfilter
+from django.utils.safestring import SafeData, mark_safe
+from django.template import resolve_variable
+from django.conf import settings
+register = Library()
+
+
+# based on: http://www.djangosnippets.org/snippets/1926/
+class RangeNode(Node):
+    def __init__(self, parser, range_args, context_name):
+        self.template_parser = parser
+        self.range_args = range_args
+        self.context_name = context_name
+
+    def render(self, context):
+
+        resolved_ranges = []
+        for arg in self.range_args:
+            compiled_arg = self.template_parser.compile_filter(arg)
+            resolved_ranges.append(compiled_arg.resolve(context,
+                        ignore_failures=True))
+        context[self.context_name] = range(*resolved_ranges)
+        return ""
+
+
+@register.tag
+def mkrange(parser, token):
+    """
+    Accepts the same arguments as the 'range' builtin and creates
+    a list containing the result of 'range'.
+
+    Syntax:
+        {% mkrange [start,] stop[, step] as context_name %}
+
+    For example:
+        {% mkrange 5 10 2 as some_range %}
+        {% for i in some_range %}
+          {{ i }}: Something I want to repeat\n
+        {% endfor %}
+
+    Produces:
+        5: Something I want to repeat
+        7: Something I want to repeat
+        9: Something I want to repeat
+    """
+
+    tokens = token.split_contents()
+    fnctl = tokens.pop(0)
+
+    def error():
+        raise TemplateSyntaxError("%s accepts the syntax: {%% %s [start,] " +
+                "stop[, step] as context_name %%}, where 'start', 'stop' " +
+                "and 'step' must all be integers." % (fnctl, fnctl))
+
+    range_args = []
+    while True:
+        if len(tokens) < 2:
+            error()
+
+        token = tokens.pop(0)
+
+        if token == "as":
+            break
+
+        range_args.append(token)
+    if len(tokens) != 1:
+        error()
+
+    context_name = tokens.pop()
+
+    return RangeNode(parser, range_args, context_name)
+
+
+def autolinebreaks(value, autoescape=None):
+    """
+    Checks if the content is html or plain text if plain text
+    replaces line breaks with appropriate HTML; a single
+    newline becomes an HTML line break (``<br />``) and a new line
+    followed by a blank line becomes a paragraph break (``</p>``).
+    """
+    import re
+    html_match = re.compile('<br>|<br />|<p>|<table>', re.IGNORECASE)
+    if not html_match.search(value):
+        from django.utils.html import linebreaks
+        autoescape = autoescape and not isinstance(value, SafeData)
+        return mark_safe(linebreaks(value, autoescape))
+    else:
+        return value
+autolinebreaks.is_safe = True
+autolinebreaks.needs_autoescape = True
+autolinebreaks = stringfilter(autolinebreaks)
+register.filter(autolinebreaks)
+
+
+@register.filter()
+def currency(value):
+    #http://djangosnippets.org/snippets/2365/
+    symbol = getattr(settings, 'CURRENCY_SYMBOL', '€')
+    thousand_sep = getattr(settings, 'THOUSAND_SEPARATOR', '.')
+    decimal_sep = getattr(settings, 'DECIMAL_SEPARATOR', ',')
+    sign = "-" if value <0 else ""
+    intstr = str(abs(int(value)))
+    f = lambda x, n, acc=[]: f(x[:-n], n, [(x[-n:])]+acc) if x else acc
+    intpart = thousand_sep.join(f(intstr, 3))
+    return "%s%s%s%s%s" % (sign, intpart, decimal_sep, ("%0.2f" % value)[-2:], symbol)
+
+@register.filter
+def hash(h, key):
+    return h[key]
+
+
+"""
+The tag generates a parameter string in form '?param1=val1&param2=val2'.
+The parameter list is generated by taking all parameters from current
+request.GET and optionally overriding them by providing parameters to the tag.
+
+This is a cleaned up version of http://djangosnippets.org/snippets/2105/. It
+solves a couple of issues, namely:
+ * parameters are optional
+ * parameters can have values from request, e.g. request.GET.foo
+ * native parsing methods are used for better compatibility and readability
+ * shorter tag name
+
+Usage: place this code in your appdir/templatetags/add_get_parameter.py
+In template:
+{% load add_get_parameter %}
+<a href="{% add_get param1='const' param2=variable_in_context %}">
+Link with modified params
+</a>
+
+It's required that you have 'django.core.context_processors.request' in
+TEMPLATE_CONTEXT_PROCESSORS
+
+Original version's URL: http://django.mar.lt/2010/07/add-get-parameter-tag.html
+"""
+
+class AddGetParameter(Node):
+    def __init__(self, values):
+        self.values = values
+
+    def render(self, context):
+        req = resolve_variable('request', context)
+        params = req.GET.copy()
+        for key, value in self.values.items():
+            params[key] = value.resolve(context)
+        return '?%s' %  params.urlencode()
+
+
+@register.tag
+def add_get(parser, token):
+    pairs = token.split_contents()[1:]
+    values = {}
+    for pair in pairs:
+        s = pair.split('=', 1)
+        values[s[0]] = parser.compile_filter(s[1])
+    return AddGetParameter(values)
+
+#From http://djangosnippets.org/snippets/294/
+@register.filter
+def classname(obj, arg=None):
+    classname = obj.__class__.__name__.lower()
+    if arg:
+        if arg.lower() == classname:
+            return True
+        else:
+            return False
+    else:
+        return classname
+
+
+@register.filter
+def in_group(user, group):
+    """Returns True/False if the user is in the given group(s).
+    Usage::
+        {% if user|in_group:"Friends" %}
+        or
+        {% if user|in_group:"Friends,Enemies" %}
+        ...
+        {% endif %}
+    You can specify a single group or comma-delimited list.
+    No white space allowed.
+
+    Credits: http://djangosnippets.org/snippets/895/
+    """
+
+    import re
+    if re.search(',', group):
+        group_list = re.sub('\s+', '', group).split(',')
+    elif re.search(' ', group):
+        group_list = group.split()
+    else:
+        group_list = [group]
+    user_groups = []
+    for group in user.groups.all():
+        user_groups.append(str(group.name))
+    return len(filter(lambda x: x in user_groups, group_list)) > 0
+in_group.is_safe = True

apsl_lib/templatetags/iker_tags.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""Utility tags and filters to get information about a django model
+or a class object in a templates. For debug purposes only
+
+Install:
+    add apsl_lib to your installed applications
+
+on your templates:
+
+    {% load iker_tags %}
+
+When you want to know to which model corresponds a var in a template just
+
+    {% details name_of_var %}
+
+this will print you the class doc, the module, the class name and its
+attributes.
+
+This is just for Django models so if it gives you an error, perhaps is
+just a normal class, so use on of the following
+
+    {{name_of_var|rawdump}}
+    {{name_of_var|dump}}
+    {{name_of_var|dir}}
+"""
+
+from django import template
+from django.template.defaultfilters import linebreaksbr
+from django.utils.html import escape
+from django.utils.safestring import mark_safe
+from pprint import pformat
+
+register = template.Library()
+
+
+def rawdump(x):
+    if hasattr(x, '__dict__'):
+        d = {
+            '__str__': str(x),
+            '__unicode__': unicode(x),
+            '__repr__': repr(x),
+        }
+        d.update(x.__dict__)
+        x = d
+    output = pformat(x) + '\n'
+    return output
+
+
+def dir(x):
+    pr = dir(x)
+    return pformat(pr)
+
+
+def dump(x):
+    return mark_safe(linebreaksbr(escape(rawdump(x))))
+
+
+class PropertyListNode(template.Node):
+    def __init__(self, model_string):
+        self.model_string = model_string
+        self.format_spec = u"<tr><td>%s</td><td>%s</td></tr>"
+
+    def render(self, context):
+        model_instance = context[self.model_string]
+        out = [u"""<table>
+            <tr><td colspan="2">%s</td>
+        """ % model_instance.__doc__.decode('utf-8')]
+        out.append(u"<tr><td>Module:</td><td>%s</td></tr>" %
+                model_instance.__class__.__module__)
+        out.append(u"<tr><td>Class:</td><td>%s</td></tr>" %
+                model_instance.__class__.__name__)
+        out.append("<tr><th>attr</th><th>valor</th></tr>")
+        for field in model_instance.__class__._meta.fields:
+            try:
+                name = field.name
+                try:
+                    attr = getattr(model_instance, field.name)
+                    try:
+                        if len(attr) > 20:
+                            attr = attr[:17] + "..."
+                    except TypeError as e:
+                        pass
+                except Exception as e:
+                    attr = e[20:]
+                out.append(self.format_spec % (name, attr))
+            except TypeError as e:
+                raise template.TemplateSyntaxError("invalid format string\
+                        specified  to property list template tag: " + str(e))
+        out.append('</table>')
+        return "".join(out)
+
+
+def property_list(parser, token):
+    """Property list tag, returns all fields of a model in the order defined"""
+    try:
+        tag_name, model = token.split_contents()
+
+    except ValueError:
+        raise template.TemplateSyntaxError("%r tag requires model" %
+                token.contents.split()[0])
+    return PropertyListNode(model)
+
+register.filter('rawdump', rawdump)
+register.filter('dump', dump)
+register.filter('dir', dir)
+register.tag('details', property_list)

apsl_lib/utils.py

+#!/usr/bin/env python
+# encoding: utf-8
+# ----------------------------------------------------------------------------
+
+
+def nicepass(alpha=6, numeric=2):
+    """
+    returns a human-readble password (say rol86din instead of
+    a difficult to remember K8Yn9muL )
+    """
+    import string
+    import random
+    vowels = ['a', 'e', 'i', 'o', 'u']
+    consonants = [a for a in string.ascii_lowercase if a not in vowels]
+    digits = string.digits
+
+    ####utility functions
+    def a_part(slen):
+        ret = ''
+        for i in range(slen):
+            if i % 2 == 0:
+                randid = random.randint(0, 20) #number of consonants
+                ret += consonants[randid]
+            else:
+                randid = random.randint(0, 4) #number of vowels
+                ret += vowels[randid]
+        return ret
+
+    def n_part(slen):
+        ret = ''
+        for i in range(slen):
+            randid = random.randint(0, 9) #number of digits
+            ret += digits[randid]
+        return ret
+
+    ####
+    fpl = alpha / 2
+    if alpha % 2 :
+        fpl = int(alpha / 2) + 1
+    lpl = alpha - fpl
+
+    start = a_part(fpl)
+    mid = n_part(numeric)
+    end = a_part(lpl)
+
+    return "%s%s%s" % (start, mid, end)
+#!/usr/bin/env python
+#-*- coding: UTF-8 -*-
+
+from setuptools import setup, find_packages
+
+setup(
+    name='apsl_lib',
+    version='0.1',
+    description='Utility libs for Django',
+    long_description=open('README').read(),
+    author='Antoni Aloy',
+    author_email='aaloy@apsl.net',
+    url='https://hg.apsl.net/apsl_lib',
+    packages=find_packages(),
+    include_package_data=True,
+    classifiers=[
+                'Development Status :: 1 - Beta',
+                'Environment :: Web Environment',
+                'Intended Audience :: Developers',
+                'License :: OSI Approved :: BSD License',
+                'Operating System :: OS Independent',
+                'Programming Language :: Python',
+                'Framework :: Django',
+                ],
+    zip_safe=False,
+)