From 8bc0bfcae2a80f5f2de459726fe83bbe5f378d77 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Mon, 30 Sep 2013 22:03:05 +0200 Subject: [PATCH] PEP8 compliance and cleanup. --- modoboa/lib/email_listing.py | 35 ++++++++++++++-------- modoboa/lib/formutils.py | 44 +++++++++++++++++---------- modoboa/lib/parameters.py | 34 ++++++++++++++------- modoboa/lib/sysutils.py | 31 ++++++++----------- modoboa/lib/tables.py | 58 ++++++++++++++---------------------- modoboa/lib/webutils.py | 15 ++-------- 6 files changed, 112 insertions(+), 105 deletions(-) diff --git a/modoboa/lib/email_listing.py b/modoboa/lib/email_listing.py index 0f066bce5..8cd0115b4 100644 --- a/modoboa/lib/email_listing.py +++ b/modoboa/lib/email_listing.py @@ -2,18 +2,20 @@ import time import re import os -import time, random, hashlib +import time +import random +import hashlib import lxml.html from lxml import etree from django.conf import settings from django.template.loader import render_to_string from django.template import Template, Context from django.utils.translation import ugettext as _ -from modoboa.lib.webutils import _render from modoboa.lib.emailutils import decode attached_map = {} + class MBconnector(object): def __init__(self, address, port): self.address = address @@ -22,6 +24,7 @@ class MBconnector(object): def messages_count(self, **kwargs): pass + class Page(object): def __init__(self, pageid, id_start, id_stop, items, items_per_page, has_previous, has_next, @@ -53,6 +56,7 @@ class Page(object): lid += 1 return lid + class Paginator(object): def __init__(self, total, elems_per_page): self.total = total @@ -65,7 +69,7 @@ class Paginator(object): id_start = self.elems_per_page * page + 1 id_stop = id_start + self.elems_per_page - 1 return (id_start, id_stop) - + def getpage(self, page): if page < 1: return None @@ -85,6 +89,7 @@ class Paginator(object): p.paginator = self return p + class EmailListing(object): def __init__(self, baseurl=None, folder=None, elems_per_page=40, @@ -113,21 +118,25 @@ class EmailListing(object): def render_navbar(page, baseurl=None): if page is None: return "" - context = {"page": page, "STATIC_URL": settings.STATIC_URL, "baseurl": baseurl} + context = { + "page": page, "STATIC_URL": settings.STATIC_URL, "baseurl": baseurl + } return render_to_string("common/pagination_bar.html", context) - + def fetch(self, request, id_start, id_stop): - table = self.tbltype(request, - self.mbc.fetch(start=id_start, stop=id_stop, - mbox=self.folder, - nbelems=self.elems_per_page)) + table = self.tbltype( + request, + self.mbc.fetch(start=id_start, stop=id_stop, + mbox=self.folder, + nbelems=self.elems_per_page) + ) tpl = Template("""
{{ table }}
""") return tpl.render( Context({ - "table" : table.render(withheader=self.show_listing_headers) + "table": table.render(withheader=self.show_listing_headers) }) ) @@ -139,10 +148,11 @@ class EmailListing(object): listing = self.fetch(request, page.id_start, page.id_stop) return dict(listing=listing, navbar=self.render_navbar(page, self.baseurl)) + def parse_search_parameters(request): - if request.GET.has_key("pattern"): + if 'pattern' in request.GET: request.session["pattern"] = re.escape(request.GET["pattern"]) - if request.GET.has_key("criteria"): + if 'criteria' in request.GET: request.session["criteria"] = request.GET["criteria"] else: request.session["criteria"] = ["from_addr"] @@ -150,4 +160,3 @@ def parse_search_parameters(request): for p in ["pattern", "criteria"]: if p in request.session.keys(): del request.session[p] - diff --git a/modoboa/lib/formutils.py b/modoboa/lib/formutils.py index 37ec8144c..fa4e62cb3 100644 --- a/modoboa/lib/formutils.py +++ b/modoboa/lib/formutils.py @@ -8,19 +8,20 @@ from django.utils.encoding import force_unicode from django.utils.safestring import mark_safe from django.utils.html import conditional_escape + class CreationWizard(object): def __init__(self, done_cb): self.steps = [] self.done_cb = done_cb def add_step(self, cls, title, buttons, formtpl=None, new_args=None): - self.steps += [dict(cls=cls, title=title, buttons=buttons, + self.steps += [dict(cls=cls, title=title, buttons=buttons, formtpl=formtpl, new_args=new_args)] def create_forms(self, data=None): for step in self.steps: args = [] - if step.has_key("new_args") and step["new_args"]: + if 'new_args' in step and step["new_args"]: args += step["new_args"] if data: args.append(data) @@ -46,6 +47,7 @@ class CreationWizard(object): def get_title(self, stepid): return "%d. %s" % (stepid + 1, self.steps[stepid]["title"]) + class DynamicForm(object): def _create_field(self, typ, name, value=None, pos=None): @@ -66,12 +68,13 @@ class DynamicForm(object): ndata = self.data.copy() values.reverse() for v in values: - if self.fields.has_key(v[0]): + if v[0] in self.fields: continue self._create_field(typ, v[0]) ndata[v[0]] = v[1] self.data = ndata + class TabForms(object): """ Simple forms container @@ -99,21 +102,21 @@ class TabForms(object): fd["instance"] = classes[fd["id"]](*args, **kwargs) else: fd["instance"] = fd["cls"](*args, **kwargs) - map(lambda fd: self.forms.remove(fd), to_remove) + self.forms = [form for form in self.forms if not form in to_remove] if self.forms: self.active_id = self.forms[0]["id"] def _before_is_valid(self, form): return True - + def is_valid(self, mandatory_only=False, optional_only=False): to_remove = [] for f in self.forms: if mandatory_only and \ - (not f.has_key("mandatory") or not f["mandatory"]): + (not 'mandatory' in f or not f["mandatory"]): continue elif optional_only and \ - (f.has_key("mandatory") and f["mandatory"]): + ('mandatory' in f and f["mandatory"]): continue if not self._before_is_valid(f): to_remove.append(f) @@ -121,7 +124,7 @@ class TabForms(object): if not f["instance"].is_valid(): self.active_id = f["id"] return False - map(lambda fd: self.forms.remove(fd), to_remove) + self.forms = [f for f in self.forms if not f in to_remove] return True def save(self, *args, **kwargs): @@ -132,7 +135,7 @@ class TabForms(object): if f["id"] == tabid: self.forms.remove(f) break - + def __iter__(self): return self.forward() @@ -144,6 +147,7 @@ class TabForms(object): # Custom fields from here # + def is_valid_host(host): """IDN compatible domain validator """ @@ -152,6 +156,7 @@ def is_valid_host(host): is_valid_host._re = re.compile(r'^([0-9a-z][-\w]*[0-9a-z]\.)+[a-z0-9\-]{2,15}$') return bool(is_valid_host._re.match(host)) + def validate_domain_name(value): if not is_valid_host(value): raise ValidationError(_('Enter a valid domain name'), 'invalid') @@ -162,8 +167,8 @@ class DomainNameField(CharField): A subclass of CharField that only accepts a valid domain name. """ default_error_messages = { - 'invalid' : _('Enter a valid domain name') - } + 'invalid': _('Enter a valid domain name') + } default_validators = [validate_domain_name] @@ -179,16 +184,23 @@ class CustomRadioInput(RadioInput): else: label_for = '' choice_label = conditional_escape(force_unicode(self.choice_label)) - return mark_safe(u'' % (label_for, self.tag(), choice_label)) + return mark_safe( + u'' + % (label_for, self.tag(), choice_label) + ) class InlineRadioRenderer(RadioSelect.renderer): def __iter__(self): for i, choice in enumerate(self.choices): - yield CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, i) + yield CustomRadioInput( + self.name, self.value, self.attrs.copy(), choice, i + ) def render(self): - return mark_safe(u'\n'.join([u'%s\n' % force_unicode(w) for w in self])) + return mark_safe( + u'\n'.join([u'%s\n' % force_unicode(w) for w in self]) + ) class InlineRadioSelect(RadioSelect): @@ -203,6 +215,8 @@ class SeparatorField(Field): class YesNoField(ChoiceField): def __init__(self, *args, **kwargs): - kwargs["choices"] = [("yes", ugettext_lazy("Yes")), ("no", ugettext_lazy("No"))] + kwargs["choices"] = [ + ("yes", ugettext_lazy("Yes")), ("no", ugettext_lazy("No")) + ] kwargs["widget"] = InlineRadioSelect super(YesNoField, self).__init__(*args, **kwargs) diff --git a/modoboa/lib/parameters.py b/modoboa/lib/parameters.py index 56d9a8590..c6989f513 100644 --- a/modoboa/lib/parameters.py +++ b/modoboa/lib/parameters.py @@ -70,14 +70,14 @@ class GenericParametersForm(forms.Form): class AdminParametersForm(GenericParametersForm): def _load_initial_values(self): - from models import Parameter + from .models import Parameter names = ["%s.%s" % (self.app, name.upper()) for name in self.fields.keys()] for p in Parameter.objects.filter(name__in=names): self.fields[p.shortname].initial = p.value def save(self): - from models import Parameter + from .models import Parameter from modoboa.lib.formutils import SeparatorField for name, value in self.cleaned_data.items(): @@ -111,7 +111,7 @@ class UserParametersForm(GenericParametersForm): def _load_initial_values(self): if self.user is None: return - from models import UserParameter + from .models import UserParameter names = ["%s.%s" % (self.app, name.upper()) for name in self.fields.keys()] for p in UserParameter.objects.filter(user=self.user, name__in=names): @@ -122,7 +122,7 @@ class UserParametersForm(GenericParametersForm): return True def save(self): - from models import UserParameter + from .models import UserParameter from modoboa.lib.formutils import SeparatorField for name, value in self.cleaned_data.items(): @@ -141,7 +141,7 @@ class UserParametersForm(GenericParametersForm): def register(formclass, label): """Register a form class containing parameters - formclass must inherit from ``AdminParametersForm`` of + formclass must inherit from ``AdminParametersForm`` or ``UserParametersForm``. :param formclass: a form class @@ -155,7 +155,9 @@ def register(formclass, label): level = 'U' else: raise RuntimeError("Unknown parameter class") - _params[level][formclass.app] = {"label": label, "form": formclass, "defaults": {}} + _params[level][formclass.app] = { + "label": label, "form": formclass, "defaults": {} + } form = formclass() for name, field in form.fields.items(): if type(field) is SeparatorField: @@ -198,7 +200,7 @@ def __guess_extension(): def save_admin(name, value, app=None): - from models import Parameter + from .models import Parameter if app is None: app = __guess_extension() @@ -215,7 +217,7 @@ def save_admin(name, value, app=None): def save_user(user, name, value, app=None): - from models import UserParameter + from .models import UserParameter if app is None: app = __guess_extension() @@ -240,7 +242,7 @@ def get_admin(name, app=None, raise_error=True): :param app: the application owning the parameter :return: the corresponding value as a string """ - from models import Parameter + from .models import Parameter if app is None: app = __guess_extension() @@ -267,7 +269,7 @@ def get_user(user, name, app=None, raise_error=True): :param app: the application owning the parameter :return: the corresponding value as a string """ - from models import UserParameter + from .models import UserParameter if app is None: app = __guess_extension() @@ -284,7 +286,13 @@ def get_user(user, name, app=None, raise_error=True): return p.value.decode("unicode_escape") -def get_sorted_apps(level, first="admin"): +def get_sorted_apps(level, first="core"): + """Retrieve the sorted list of all registerd applications. + + :param str level: application level + :param str first: force the first item of the result + :rtype: list + """ sorted_apps = [] if first in _params[level]: sorted_apps.append(first) @@ -296,6 +304,10 @@ def get_sorted_apps(level, first="admin"): def get_admin_forms(*args, **kwargs): + """Get all admin level forms. + + Generates an instance of each declared form. + """ for app in get_sorted_apps('A'): formdef = _params['A'][app] yield {"label": formdef["label"], diff --git a/modoboa/lib/sysutils.py b/modoboa/lib/sysutils.py index 2358760cd..8ce692064 100644 --- a/modoboa/lib/sysutils.py +++ b/modoboa/lib/sysutils.py @@ -4,29 +4,24 @@ This module extra functions/shortcuts to communicate with the system (executing commands, etc.) """ -import logging -import logging.handlers +import subprocess from modoboa.lib import parameters -def exec_cmd(cmd, sudo_user=None, **kwargs): - import subprocess +def exec_cmd(cmd, sudo_user=None, **kwargs): + """Execute a shell command. + + Run a command using the current user. Set :keyword:`sudo_user` if + you need different privileges. + + :param str cmd: the command to execute + :param str sudo_user: a valid system username + :rtype: tuple + :return: return code, command output + """ if sudo_user is not None: cmd = "sudo -u %s %s" % (sudo_user, cmd) - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs) output = p.communicate()[0] return p.returncode, output - -def __log(msg, facility=logging.handlers.SysLogHandler.LOG_AUTH): - logger = logging.getLogger('modoboa') - logger.setLevel(logging.DEBUG) - handler = logging.handlers.SysLogHandler(address='/dev/log', facility=facility) - formatter = logging.Formatter('%(name)s: %(levelname)s %(message)s') - handler.setFormatter(formatter) - logger.addHandler(handler) - return logger - -def log_warning(msg): - logger = __log(msg) - logger.warning(msg) diff --git a/modoboa/lib/tables.py b/modoboa/lib/tables.py index 5d696c990..5ea8814a7 100644 --- a/modoboa/lib/tables.py +++ b/modoboa/lib/tables.py @@ -16,6 +16,7 @@ from django.template import Template, RequestContext, Context from django.template.loader import render_to_string from templatetags.libextras import render_link + class Column(object): """Simple column representation """ @@ -24,7 +25,7 @@ class Column(object): self.sortable = True for k, v in kwargs.iteritems(): setattr(self, k, v) - + def __unicode__(self): try: label = getattr(self, "label") @@ -51,6 +52,7 @@ class Column(object): except AttributeError: pass + class SelectionColumn(Column): """Specific column: selection @@ -64,7 +66,7 @@ class SelectionColumn(Column): def render(self, value, selection): return "" \ - % {'id': self.name, 'value': value, + % {'id': self.name, 'value': value, "checked": "checked=''" if selection else ""} def transform(self, row, col, table): @@ -72,9 +74,10 @@ class SelectionColumn(Column): col["value"] = self.render(row[table.idkey], selection) col["safe"] = True + class ImgColumn(Column): """Specific column: image - + This kind of column only contains images tags (). """ def __str__(self): @@ -86,7 +89,7 @@ class ImgColumn(Column): def render(self, value): if type(value) in [list, tuple]: - return "".join(map(lambda i: "" % i, value)) + return "".join(["" % i for i in value]) return "" % value def transform(self, row, col, table): @@ -100,6 +103,7 @@ class ImgColumn(Column): pass col["safe"] = True + class DivColumn(Column): def __str__(self): return "" @@ -111,6 +115,7 @@ class DivColumn(Column): col["value"] = self.render() col["safe"] = True + class ActionColumn(Column): def render(self, fct, user, rowid): return fct(user, rowid) @@ -119,10 +124,11 @@ class ActionColumn(Column): col["value"] = self.render(self.defvalue, table.request.user, row[table.idkey]) col["safe"] = True + class LinkColumn(Column): def render(self, rowid, value): linkdef = dict(label=value, modal=self.modal) - if type(self.urlpattern) == dict: + if type(self.urlpattern) is dict: t, value = rowid.split(":") linkdef.update(url=reverse(self.urlpattern[t], args=[value]), modalcb=self.modalcb[t]) @@ -135,12 +141,15 @@ class LinkColumn(Column): col["value"] = self.render(row[table.idkey], row[self.name]) col["safe"] = True + class Table(object): tableid = "" - def __init__(self, request, rows={}): + def __init__(self, request, rows=None): self.columns = [] self.request = request + if rows is None: + rows = {} try: order = getattr(self, "cols_order") except AttributeError: @@ -168,13 +177,13 @@ class Table(object): self.rows = [] trcpt = 0 for row in rows: - nrow = {"id" : row[self.idkey], "cols" : [], "trcpt" : trcpt} + nrow = {"id": row[self.idkey], "cols": [], "trcpt": trcpt} for name in ["style", "options"]: - if row.has_key(name): + if name in row: nrow[name] = row[name] - + for c in self.columns: - newcol = {"name" : c.name} + newcol = {"name": c.name} for key in ["width", "align", "cssclass"]: try: newcol[key] = getattr(c, key) @@ -184,7 +193,7 @@ class Table(object): nrow["cols"] += [newcol] self.rows += [nrow] trcpt += 1 - + def _rows_from_model(self, objects, include_type_in_id=False): rows = [] for obj in objects: @@ -232,32 +241,11 @@ class Table(object): """) return t.render(RequestContext(self.request, { - "table" : self, "tableid" : self.tableid, "styles" : styles, - "withheader" : withheader - })) + "table": self, "tableid": self.tableid, "styles": styles, + "withheader": withheader + })) t = Template("""
%s
""" % _("No entries to display")) return t.render(Context()) - - def render_head(self, request): - t = Template(""" - - {% include "common/table_head.html" %} -
-""") - return t.render(Context({ - "table" : self, "tableid" : "%s_head" % self.tableid - })) - - def render_body(self, request): - t = Template(""" - - {% include "common/table_body.html" %} -
-""") - return t.render(Context({ - "table" : self, "tableid" : "%s_body" % self.tableid - })) - diff --git a/modoboa/lib/webutils.py b/modoboa/lib/webutils.py index 28ac626a5..c9977d244 100644 --- a/modoboa/lib/webutils.py +++ b/modoboa/lib/webutils.py @@ -15,23 +15,12 @@ from django.utils import simplejson from django.conf import settings -def _render(request, tpl, user_context): - """Custom rendering function +def _render_to_string(request, tpl, user_context): + """Custom rendering function. Just a wrapper which automatically adds a RequestContext instance (useful to use settings variables like STATIC_URL inside templates) """ - return render_to_response( - tpl, user_context, - context_instance=template.RequestContext(request) - ) - - -def _render_to_string(request, tpl, user_context): - """Custom rendering function - - Same as _render. - """ return render_to_string(tpl, user_context, context_instance=template.RequestContext(request))