diff --git a/deluge/ui/webui/LICENSE b/deluge/ui/webui/LICENSE
deleted file mode 100644
index 94a045322..000000000
--- a/deluge/ui/webui/LICENSE
+++ /dev/null
@@ -1,621 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
-
- No data. s."
- return self._html_output_filtered(u' %(label)s %(field)s%(help_text)s %s
-
- """ % {'active_port':sclient.get_listen_port()}
-
-config_page.register('network','ports', NetworkPorts)
-
-class NetworkExtra(config_forms.CfgForm ):
- title = _("Extra's")
- dht = forms.CheckBox(_("Mainline DHT"))
- upnp = forms.CheckBox(_("UpNP"))
- natpmp = forms.CheckBox(_("NAT-PMP"))
- utpex = forms.CheckBox(_("Peer-Exchange"))
- lsd = forms.CheckBox(_("LSD"))
-
-config_page.register('network','extra', NetworkExtra)
-
-class NetworkEnc(config_forms.CfgForm ):
- title = _("Encryption")
-
- _enc_choices = list(enumerate([_("Forced"),_("Enabled"),_("Disabled")]))
- _level_choices = list(enumerate([_("Handshake"), _("Full") , _("Either")]))
-
- enc_in_policy = forms.IntChoiceField(_("Inbound"), _enc_choices)
- enc_out_policy = forms.IntChoiceField(_("Outbound"), _enc_choices)
- enc_level = forms.IntChoiceField(_("Level"), _level_choices)
- enc_prefer_rc4 = forms.CheckBox("Prefer to encrypt entire stream")
-
-config_page.register('network','encryption', NetworkEnc)
-
-class Proxy(config_forms.CfgForm):
- title = _("Proxy")
- _type_choices = list(enumerate(
- [_("None"), _("Socksv4"), _("Socksv5"), _("Socksv5 W/ Auth"),_("HTTP"), _("HTTP W/ Auth")]))
-
- proxy_type = forms.IntChoiceField(_("Type"), _type_choices)
- proxy_server =forms.CharField(label= _("Host"),required=False)
- proxy_port = forms.IntegerField(label= _("Port"),min_value = 0, max_value=65535 , required=False)
- proxy_username = forms.CharField(label= _("Username"), required=False)
- proxy_password = forms.Password(label= _("Password"), required=False)
-
-config_page.register('network','proxy', Proxy)
-
-class BandwithGlobal(config_forms.CfgForm):
- title = _("Global")
- info = _("-1 = Unlimited")
- max_connections_global = forms.DelugeInt(_("Maximum Connections"))
- max_download_speed = forms.DelugeFloat(_("Maximum Download Speed (Kib/s)"))
- max_upload_speed = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
- max_upload_slots_global = forms.DelugeInt(_("Maximum Upload Slots"))
-
- max_half_open_connections = forms.DelugeInt(_("Maximum Half-Open Connections"))
- max_connections_per_second = forms.DelugeInt(_("Maximum Connection Attempts per Second"))
- ignore_limits_on_local_network = forms.CheckBox(_("Ignore limits on local network"))
- rate_limit_ip_overhead = forms.CheckBox(_("Rate Limit IP Overhead"))
-
-
-config_page.register('bandwidth','global', BandwithGlobal)
-
-class BandwithTorrent(config_forms.CfgForm):
- title = _("Per Torrent")
- info = _("-1 = Unlimited")
- max_connections_per_torrent = forms.DelugeInt(_("Maximum Connections"))
- max_download_speed_per_torrent = forms.DelugeFloat(_("Maximum Download Speed (Kib/s)"))
- max_upload_speed_per_torrent = forms.DelugeFloat(_("Maximum Upload Speed (Kib/s)"))
- max_upload_slots_per_torrent = forms.DelugeInt(_("Maximum Upload Slots"))
-
-config_page.register('bandwidth','torrent', BandwithTorrent)
-
-class Download(config_forms.CfgForm):
- title = _("Download")
- download_location = forms.ServerFolder(_("Store all downoads in"))
- torrentfiles_location = forms.ServerFolder(_("Save .torrent files to"))
- autoadd_location = forms.ServerFolder(_("Auto Add folder"), required=False)
- autoadd_enable = forms.CheckBox(_("Auto Add enabled"))
- compact_allocation = forms.CheckBox(_('Use Compact Allocation'))
- prioritize_first_last_pieces = forms.CheckBox(_('Prioritize first and last pieces'))
- #default_private = forms.CheckBox(_('Set private flag by default'))
-
-config_page.register('deluge','download', Download)
-
-class Daemon(config_forms.CfgForm):
- title = _("Daemon")
- info = _("Restart daemon and webui after changing these settings")
- daemon_port = forms.IntegerField(_("Port"))
- allow_remote = forms.CheckBox(_("Allow Remote Connections"))
-
-config_page.register('deluge','daemon', Daemon)
-
-class Queue(config_forms.CfgForm):
- title = _("Queue")
- info = _("-1 = unlimited")
-
- queue_new_to_top = forms.CheckBox(_("Queue new torrents to top"))
-
-
- #total_downloading = forms.DelugeInt(_("Total active downloading"))
- max_active_limit = forms.DelugeInt(_("Total active torrents"))
- max_active_downloading = forms.DelugeInt(_("Total active downloading"))
- max_active_seeding = forms.DelugeInt(_("Total active seeding"))
-
-
- share_ratio_limit = forms.FloatField(min_value=-1)
- seed_time_ratio_limit = forms.FloatField(min_value=-1)
- seed_time_limit = forms.FloatField(min_value=-1)
-
- stop_seed_at_ratio = forms.CheckBox(_("Stop seeding when ratio reaches"))
- #stop_ratio = forms.FloatField(min_value=-1)
- remove_seed_at_ratio = forms.CheckBox(_("Remove torrent when ratio reached"))
- stop_seed_ratio = forms.FloatField(min_value=-1)
-
-config_page.register('deluge','queue', Queue)
-
-"""
-Will become a plugin, saved for later use.
-class Notification(config_forms.CfgForm):
- title = _("Notification")
- _security_choices = [(t,t) for t in [None,"SSL","TLS"]]
- ntf_email = forms.EmailField(label=_("Email"), required=False)
- ntf_server =forms.CharField(label= _("Server"), required=False)
- ntf_username = forms.CharField(label= _("Username"), required=False)
- ntf_password = forms.CharField(label= _("Password"), required=False)
- ntf_security = forms.ChoiceField( label=_("Security"), choices = _security_choices )
-
-config_page.register('deluge','notification', Notification)
-"""
-
-class Plugins(forms.Form):
- title = _("Enabled Plugins")
-
- enabled_plugins = forms.LazyMultipleChoice(
- choices_getter = lambda: [(p,p) for p in sclient.get_available_plugins()]
- )
-
- def initial_data(self):
- return {'enabled_plugins':sclient.get_enabled_plugins()}
-
- def save(self, data):
- new_plugins = data.enabled_plugins
- old_plugins = sclient.get_enabled_plugins()
-
- enable = [p for p in new_plugins if p not in old_plugins]
- disable = [p for p in old_plugins if p not in new_plugins]
-
-
- plugin_manager = component.get("WebPluginManager")
- for p in enable:
- sclient.enable_plugin(p)
- plugin_manager.enable_plugin(p)
-
- for p in disable:
- sclient.disable_plugin(p)
- plugin_manager.disable_plugin(p)
-
-config_page.register('deluge','plugins', Plugins)
-
diff --git a/deluge/ui/webui/config_tabs_webui.py b/deluge/ui/webui/config_tabs_webui.py
deleted file mode 100644
index c1a73a2d8..000000000
--- a/deluge/ui/webui/config_tabs_webui.py
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# deluge_webserver.py
-#
-# Copyright (C) Martijn Voncken 2008
- Unable to reconnect, please restart deluge.
- """,
-"InvalidUniqueIDError:":
- """
- this torrent was removed,
- click here to go to the torrent-list
- """
-}
-
-
-pretty_errors_cls = {
- type(utils.UnknownTorrentError):"""
- this torrent was removed,
- click here to go to the torrent-list
- """
-}
-
-import sys, urlparse, pprint
-from web import websafe
-from web import template
-import web #import lib.webpy022.webapi as web
-import webserver_common as ws
-from traceback import format_tb
-from deluge import common
-
-Template = template.Template
-
-import os, os.path
-whereami = os.path.join(os.getcwd(), __file__)
-whereami = os.path.sep.join(whereami.split(os.path.sep)[:-1])
-djangoerror_t = """\
-$def with (exception_type, exception_value, frames, exception_message, version_info, tback_txt)
-
-
-
-
-
-
-
-
-
- Oops, Deluge Broke ...
- You might have found a bug, or you did something really stupid ;-).
-
If the error persists :
- Read the Faq.
- Try downloading the latest version at
- deluge-torrent.org
-
Visit the forum
- or the buglist for more info.
-
-$exception_type : $exception_value
-
-Try to explain what you where doing,
-and how you could work around the problem.
-Don't paste without context and expect us to know what went wrong.
-
-
-
-
-Use a pastebin on IRC!
-
-
-
-
-Traceback (innermost first)
-
-$for frame in frames:
-
-$frame.filename in $frame.function
- $if frame.context_line:
-
- $for line in frame.pre_context:
-
-
- $if frame.post_context:
-
- $for line in frame.post_context:
-
- Response so far
- HEADERS
-
- $for kv in ctx.headers:
- $kv[0]: $kv[1]
- $else:
- [no headers]
- BODY
-
- $ctx.output
- Request information
-
-INPUT
-$:dicttable(web.input())
-
-COOKIES
-$:dicttable(web.cookies())
-
-META
-$ newctx = []
-$# ) and (k not in ['env', 'output', 'headers', 'environ', 'status', 'db_execute']):
-$for k, v in ctx.iteritems():
- $if not k.startswith('_') and (k in x):
- $newctx.append(kv)
-$:dicttable(dict(newctx))
-
-ENVIRONMENT
-$:dicttable(ctx.env)
-
-$else:
-
-
- $ temp = d.items()
- $temp.sort()
- $for kv in temp:
- Variable Value
-
- $kv[0] s -- excluding the ."
- return self._html_output_filtered(u'
', u'%(label)s %(errors)s%(field)s%(help_text)s ', '', u'%s
%s', False, filter)
-
- def as_ul(self, filter = None):
- "Returns this form rendered as HTML ."
- return self._html_output_filtered(u'
(?:%s).*?[a-zA-Z].*?
\s*)+)' % '|'.join([re.escape(x) for x in DOTS]), re.DOTALL) -trailing_empty_content_re = re.compile(r'(?:(?: |\s|
)*?
and
s."""
- value = re.sub(r'\r\n|\r|\n', '\n', force_unicode(value)) # normalize newlines
- paras = re.split('\n{2,}', value)
- if autoescape:
- paras = [u'
%s
' % escape(p.strip()).replace('\n', '%s
' % p.strip().replace('\n', '", but only if it's at the - bottom of the text. - """ - from django.utils.text import normalize_newlines - text = normalize_newlines(force_unicode(text)) - text = re.sub(r'<(/?)\s*b\s*>', '<\\1strong>', text) - text = re.sub(r'<(/?)\s*i\s*>', '<\\1em>', text) - text = fix_ampersands(text) - # Remove all target="" attributes from tags. - text = link_target_attribute_re.sub('\\1', text) - # Trim stupid HTML such as
%s' % d, '
", but only if it's at the bottom - # of the text. - text = trailing_empty_content_re.sub('', text) - return text -clean_html = allow_lazy(clean_html, unicode) diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/http.py b/deluge/ui/webui/lib/newforms_portable/django/utils/http.py deleted file mode 100644 index db8bb9644..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/http.py +++ /dev/null @@ -1,67 +0,0 @@ -import urllib -from email.Utils import formatdate - -from encoding import smart_str, force_unicode -from functional import allow_lazy - -def urlquote(url, safe='/'): - """ - A version of Python's urllib.quote() function that can operate on unicode - strings. The url is first UTF-8 encoded before quoting. The returned string - can safely be used as part of an argument to a subsequent iri_to_uri() call - without double-quoting occurring. - """ - return force_unicode(urllib.quote(smart_str(url), safe)) - -urlquote = allow_lazy(urlquote, unicode) - -def urlquote_plus(url, safe=''): - """ - A version of Python's urllib.quote_plus() function that can operate on - unicode strings. The url is first UTF-8 encoded before quoting. The - returned string can safely be used as part of an argument to a subsequent - iri_to_uri() call without double-quoting occurring. - """ - return force_unicode(urllib.quote_plus(smart_str(url), safe)) -urlquote_plus = allow_lazy(urlquote_plus, unicode) - -def urlencode(query, doseq=0): - """ - A version of Python's urllib.urlencode() function that can operate on - unicode strings. The parameters are first case to UTF-8 encoded strings and - then encoded as per normal. - """ - if hasattr(query, 'items'): - query = query.items() - return urllib.urlencode( - [(smart_str(k), - isinstance(v, (list,tuple)) and [smart_str(i) for i in v] or smart_str(v)) - for k, v in query], - doseq) - -def cookie_date(epoch_seconds=None): - """ - Formats the time to ensure compatibility with Netscape's cookie standard. - - Accepts a floating point number expressed in seconds since the epoch, in - UTC - such as that outputted by time.time(). If set to None, defaults to - the current time. - - Outputs a string in the format 'Wdy, DD-Mon-YYYY HH:MM:SS GMT'. - """ - rfcdate = formatdate(epoch_seconds) - return '%s-%s-%s GMT' % (rfcdate[:7], rfcdate[8:11], rfcdate[12:25]) - -def http_date(epoch_seconds=None): - """ - Formats the time to match the RFC1123 date format as specified by HTTP - RFC2616 section 3.3.1. - - Accepts a floating point number expressed in seconds since the epoch, in - UTC - such as that outputted by time.time(). If set to None, defaults to - the current time. - - Outputs a string in the format 'Wdy, DD Mon YYYY HH:MM:SS GMT'. - """ - rfcdate = formatdate(epoch_seconds) - return '%s GMT' % rfcdate[:25] diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/safestring.py b/deluge/ui/webui/lib/newforms_portable/django/utils/safestring.py deleted file mode 100644 index 99658fb8b..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/safestring.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -Functions for working with "safe strings": strings that can be displayed safely -without further escaping in HTML. Marking something as a "safe string" means -that the producer of the string has already turned characters that should not -be interpreted by the HTML engine (e.g. '<') into the appropriate entities. -""" -from functional import curry, Promise - -class EscapeData(object): - pass - -class EscapeString(str, EscapeData): - """ - A string that should be HTML-escaped when output. - """ - pass - -class EscapeUnicode(unicode, EscapeData): - """ - A unicode object that should be HTML-escaped when output. - """ - pass - -class SafeData(object): - pass - -class SafeString(str, SafeData): - """ - A string subclass that has been specifically marked as "safe" (requires no - further escaping) for HTML output purposes. - """ - def __add__(self, rhs): - """ - Concatenating a safe string with another safe string or safe unicode - object is safe. Otherwise, the result is no longer safe. - """ - t = super(SafeString, self).__add__(rhs) - if isinstance(rhs, SafeUnicode): - return SafeUnicode(t) - elif isinstance(rhs, SafeString): - return SafeString(t) - return t - - def _proxy_method(self, *args, **kwargs): - """ - Wrap a call to a normal unicode method up so that we return safe - results. The method that is being wrapped is passed in the 'method' - argument. - """ - method = kwargs.pop('method') - data = method(self, *args, **kwargs) - if isinstance(data, str): - return SafeString(data) - else: - return SafeUnicode(data) - - decode = curry(_proxy_method, method = str.decode) - -class SafeUnicode(unicode, SafeData): - """ - A unicode subclass that has been specifically marked as "safe" for HTML - output purposes. - """ - def __add__(self, rhs): - """ - Concatenating a safe unicode object with another safe string or safe - unicode object is safe. Otherwise, the result is no longer safe. - """ - t = super(SafeUnicode, self).__add__(rhs) - if isinstance(rhs, SafeData): - return SafeUnicode(t) - return t - - def _proxy_method(self, *args, **kwargs): - """ - Wrap a call to a normal unicode method up so that we return safe - results. The method that is being wrapped is passed in the 'method' - argument. - """ - method = kwargs.pop('method') - data = method(self, *args, **kwargs) - if isinstance(data, str): - return SafeString(data) - else: - return SafeUnicode(data) - - encode = curry(_proxy_method, method = unicode.encode) - -def mark_safe(s): - """ - Explicitly mark a string as safe for (HTML) output purposes. The returned - object can be used everywhere a string or unicode object is appropriate. - - Can be called multiple times on a single string. - """ - if isinstance(s, SafeData): - return s - if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str): - return SafeString(s) - if isinstance(s, (unicode, Promise)): - return SafeUnicode(s) - return SafeString(str(s)) - -def mark_for_escaping(s): - """ - Explicitly mark a string as requiring HTML escaping upon output. Has no - effect on SafeData subclasses. - - Can be called multiple times on a single string (the resulting escaping is - only applied once). - """ - if isinstance(s, (SafeData, EscapeData)): - return s - if isinstance(s, str) or (isinstance(s, Promise) and s._delegate_str): - return EscapeString(s) - if isinstance(s, (unicode, Promise)): - return EscapeUnicode(s) - return EscapeString(str(s)) - diff --git a/deluge/ui/webui/lib/newforms_portable/django/utils/translation.py b/deluge/ui/webui/lib/newforms_portable/django/utils/translation.py deleted file mode 100644 index ad65bd959..000000000 --- a/deluge/ui/webui/lib/newforms_portable/django/utils/translation.py +++ /dev/null @@ -1,9 +0,0 @@ -try: - _('translate something') -except: - import gettext - gettext.install('locale') - -ugettext = _ -ugettext_lazy = _ - diff --git a/deluge/ui/webui/lib/newforms_portable/fields.py b/deluge/ui/webui/lib/newforms_portable/fields.py deleted file mode 100644 index c20899ada..000000000 --- a/deluge/ui/webui/lib/newforms_portable/fields.py +++ /dev/null @@ -1,784 +0,0 @@ -""" -Field classes. -""" - -import copy -import datetime -import os -import re -import time -# Python 2.3 fallbacks -try: - from decimal import Decimal, DecimalException -except ImportError: - from django.utils._decimal import Decimal, DecimalException -try: - set -except NameError: - from sets import Set as set - -from django.utils.translation import ugettext_lazy as _ -from django.utils.encoding import StrAndUnicode, smart_unicode, smart_str - -from util import ErrorList, ValidationError -from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput - - -__all__ = ( - 'Field', 'CharField', 'IntegerField', - 'DEFAULT_DATE_INPUT_FORMATS', 'DateField', - 'DEFAULT_TIME_INPUT_FORMATS', 'TimeField', - 'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField', - 'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', - 'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', - 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', - 'SplitDateTimeField', 'IPAddressField', 'FilePathField', -) - -# These values, if given to to_python(), will trigger the self.required check. -EMPTY_VALUES = (None, '') - - -class Field(object): - widget = TextInput # Default widget to use when rendering this type of Field. - hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". - default_error_messages = { - 'required': _(u'This field is required.'), - 'invalid': _(u'Enter a valid value.'), - } - - # Tracks each time a Field instance is created. Used to retain order. - creation_counter = 0 - - def __init__(self, required=True, widget=None, label=None, initial=None, - help_text=None, error_messages=None): - # required -- Boolean that specifies whether the field is required. - # True by default. - # widget -- A Widget class, or instance of a Widget class, that should - # be used for this Field when displaying it. Each Field has a - # default Widget that it'll use if you don't specify this. In - # most cases, the default widget is TextInput. - # label -- A verbose name for this field, for use in displaying this - # field in a form. By default, Django will use a "pretty" - # version of the form field name, if the Field is part of a - # Form. - # initial -- A value to use in this Field's initial display. This value - # is *not* used as a fallback if data isn't given. - # help_text -- An optional string to use as "help text" for this Field. - if label is not None: - label = smart_unicode(label) - self.required, self.label, self.initial = required, label, initial - self.help_text = smart_unicode(help_text or '') - widget = widget or self.widget - if isinstance(widget, type): - widget = widget() - - # Hook into self.widget_attrs() for any Field-specific HTML attributes. - extra_attrs = self.widget_attrs(widget) - if extra_attrs: - widget.attrs.update(extra_attrs) - - self.widget = widget - - # Increase the creation counter, and save our local copy. - self.creation_counter = Field.creation_counter - Field.creation_counter += 1 - - def set_class_error_messages(messages, klass): - for base_class in klass.__bases__: - set_class_error_messages(messages, base_class) - messages.update(getattr(klass, 'default_error_messages', {})) - - messages = {} - set_class_error_messages(messages, self.__class__) - messages.update(error_messages or {}) - self.error_messages = messages - - def clean(self, value): - """ - Validates the given value and returns its "cleaned" value as an - appropriate Python object. - - Raises ValidationError for any errors. - """ - if self.required and value in EMPTY_VALUES: - raise ValidationError(self.error_messages['required']) - return value - - def widget_attrs(self, widget): - """ - Given a Widget instance (*not* a Widget class), returns a dictionary of - any HTML attributes that should be added to the Widget, based on this - Field. - """ - return {} - - def __deepcopy__(self, memo): - result = copy.copy(self) - memo[id(self)] = result - result.widget = copy.deepcopy(self.widget, memo) - return result - -class CharField(Field): - default_error_messages = { - 'max_length': _(u'Ensure this value has at most %(max)d characters (it has %(length)d).'), - 'min_length': _(u'Ensure this value has at least %(min)d characters (it has %(length)d).'), - } - - def __init__(self, max_length=None, min_length=None, *args, **kwargs): - self.max_length, self.min_length = max_length, min_length - super(CharField, self).__init__(*args, **kwargs) - - def clean(self, value): - "Validates max_length and min_length. Returns a Unicode object." - super(CharField, self).clean(value) - if value in EMPTY_VALUES: - return u'' - value = smart_unicode(value) - value_length = len(value) - if self.max_length is not None and value_length > self.max_length: - raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length}) - if self.min_length is not None and value_length < self.min_length: - raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length}) - return value - - def widget_attrs(self, widget): - if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): - # The HTML attribute is maxlength, not max_length. - return {'maxlength': str(self.max_length)} - -class IntegerField(Field): - default_error_messages = { - 'invalid': _(u'Enter a whole number.'), - 'max_value': _(u'Ensure this value is less than or equal to %s.'), - 'min_value': _(u'Ensure this value is greater than or equal to %s.'), - } - - def __init__(self, max_value=None, min_value=None, *args, **kwargs): - self.max_value, self.min_value = max_value, min_value - super(IntegerField, self).__init__(*args, **kwargs) - - def clean(self, value): - """ - Validates that int() can be called on the input. Returns the result - of int(). Returns None for empty values. - """ - super(IntegerField, self).clean(value) - if value in EMPTY_VALUES: - return None - try: - value = int(str(value)) - except (ValueError, TypeError): - raise ValidationError(self.error_messages['invalid']) - if self.max_value is not None and value > self.max_value: - raise ValidationError(self.error_messages['max_value'] % self.max_value) - if self.min_value is not None and value < self.min_value: - raise ValidationError(self.error_messages['min_value'] % self.min_value) - return value - -class FloatField(Field): - default_error_messages = { - 'invalid': _(u'Enter a number.'), - 'max_value': _(u'Ensure this value is less than or equal to %s.'), - 'min_value': _(u'Ensure this value is greater than or equal to %s.'), - } - - def __init__(self, max_value=None, min_value=None, *args, **kwargs): - self.max_value, self.min_value = max_value, min_value - Field.__init__(self, *args, **kwargs) - - def clean(self, value): - """ - Validates that float() can be called on the input. Returns a float. - Returns None for empty values. - """ - super(FloatField, self).clean(value) - if not self.required and value in EMPTY_VALUES: - return None - try: - value = float(value) - except (ValueError, TypeError): - raise ValidationError(self.error_messages['invalid']) - if self.max_value is not None and value > self.max_value: - raise ValidationError(self.error_messages['max_value'] % self.max_value) - if self.min_value is not None and value < self.min_value: - raise ValidationError(self.error_messages['min_value'] % self.min_value) - return value - -class DecimalField(Field): - default_error_messages = { - 'invalid': _(u'Enter a number.'), - 'max_value': _(u'Ensure this value is less than or equal to %s.'), - 'min_value': _(u'Ensure this value is greater than or equal to %s.'), - 'max_digits': _('Ensure that there are no more than %s digits in total.'), - 'max_decimal_places': _('Ensure that there are no more than %s decimal places.'), - 'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.') - } - - def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs): - self.max_value, self.min_value = max_value, min_value - self.max_digits, self.decimal_places = max_digits, decimal_places - Field.__init__(self, *args, **kwargs) - - def clean(self, value): - """ - Validates that the input is a decimal number. Returns a Decimal - instance. Returns None for empty values. Ensures that there are no more - than max_digits in the number, and no more than decimal_places digits - after the decimal point. - """ - super(DecimalField, self).clean(value) - if not self.required and value in EMPTY_VALUES: - return None - value = smart_str(value).strip() - try: - value = Decimal(value) - except DecimalException: - raise ValidationError(self.error_messages['invalid']) - pieces = str(value).lstrip("-").split('.') - decimals = (len(pieces) == 2) and len(pieces[1]) or 0 - digits = len(pieces[0]) - if self.max_value is not None and value > self.max_value: - raise ValidationError(self.error_messages['max_value'] % self.max_value) - if self.min_value is not None and value < self.min_value: - raise ValidationError(self.error_messages['min_value'] % self.min_value) - if self.max_digits is not None and (digits + decimals) > self.max_digits: - raise ValidationError(self.error_messages['max_digits'] % self.max_digits) - if self.decimal_places is not None and decimals > self.decimal_places: - raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places) - if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places): - raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) - return value - -DEFAULT_DATE_INPUT_FORMATS = ( - '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' - '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006' - '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006' - '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006' - '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006' -) - -class DateField(Field): - default_error_messages = { - 'invalid': _(u'Enter a valid date.'), - } - - def __init__(self, input_formats=None, *args, **kwargs): - super(DateField, self).__init__(*args, **kwargs) - self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS - - def clean(self, value): - """ - Validates that the input can be converted to a date. Returns a Python - datetime.date object. - """ - super(DateField, self).clean(value) - if value in EMPTY_VALUES: - return None - if isinstance(value, datetime.datetime): - return value.date() - if isinstance(value, datetime.date): - return value - for format in self.input_formats: - try: - return datetime.date(*time.strptime(value, format)[:3]) - except ValueError: - continue - raise ValidationError(self.error_messages['invalid']) - -DEFAULT_TIME_INPUT_FORMATS = ( - '%H:%M:%S', # '14:30:59' - '%H:%M', # '14:30' -) - -class TimeField(Field): - default_error_messages = { - 'invalid': _(u'Enter a valid time.') - } - - def __init__(self, input_formats=None, *args, **kwargs): - super(TimeField, self).__init__(*args, **kwargs) - self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS - - def clean(self, value): - """ - Validates that the input can be converted to a time. Returns a Python - datetime.time object. - """ - super(TimeField, self).clean(value) - if value in EMPTY_VALUES: - return None - if isinstance(value, datetime.time): - return value - for format in self.input_formats: - try: - return datetime.time(*time.strptime(value, format)[3:6]) - except ValueError: - continue - raise ValidationError(self.error_messages['invalid']) - -DEFAULT_DATETIME_INPUT_FORMATS = ( - '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' - '%Y-%m-%d %H:%M', # '2006-10-25 14:30' - '%Y-%m-%d', # '2006-10-25' - '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59' - '%m/%d/%Y %H:%M', # '10/25/2006 14:30' - '%m/%d/%Y', # '10/25/2006' - '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59' - '%m/%d/%y %H:%M', # '10/25/06 14:30' - '%m/%d/%y', # '10/25/06' -) - -class DateTimeField(Field): - widget = DateTimeInput - default_error_messages = { - 'invalid': _(u'Enter a valid date/time.'), - } - - def __init__(self, input_formats=None, *args, **kwargs): - super(DateTimeField, self).__init__(*args, **kwargs) - self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS - - def clean(self, value): - """ - Validates that the input can be converted to a datetime. Returns a - Python datetime.datetime object. - """ - super(DateTimeField, self).clean(value) - if value in EMPTY_VALUES: - return None - if isinstance(value, datetime.datetime): - return value - if isinstance(value, datetime.date): - return datetime.datetime(value.year, value.month, value.day) - if isinstance(value, list): - # Input comes from a SplitDateTimeWidget, for example. So, it's two - # components: date and time. - if len(value) != 2: - raise ValidationError(self.error_messages['invalid']) - value = '%s %s' % tuple(value) - for format in self.input_formats: - try: - return datetime.datetime(*time.strptime(value, format)[:6]) - except ValueError: - continue - raise ValidationError(self.error_messages['invalid']) - -class RegexField(CharField): - def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs): - """ - regex can be either a string or a compiled regular expression object. - error_message is an optional error message to use, if - 'Enter a valid value' is too generic for you. - """ - # error_message is just kept for backwards compatibility: - if error_message: - error_messages = kwargs.get('error_messages') or {} - error_messages['invalid'] = error_message - kwargs['error_messages'] = error_messages - super(RegexField, self).__init__(max_length, min_length, *args, **kwargs) - if isinstance(regex, basestring): - regex = re.compile(regex) - self.regex = regex - - def clean(self, value): - """ - Validates that the input matches the regular expression. Returns a - Unicode object. - """ - value = super(RegexField, self).clean(value) - if value == u'': - return value - if not self.regex.search(value): - raise ValidationError(self.error_messages['invalid']) - return value - -email_re = re.compile( - r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom - r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string - r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain - -class EmailField(RegexField): - default_error_messages = { - 'invalid': _(u'Enter a valid e-mail address.'), - } - - def __init__(self, max_length=None, min_length=None, *args, **kwargs): - RegexField.__init__(self, email_re, max_length, min_length, *args, - **kwargs) - -try: - from django.conf import settings - URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT -except ImportError: - # It's OK if Django settings aren't configured. - URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)' - -class UploadedFile(StrAndUnicode): - "A wrapper for files uploaded in a FileField" - def __init__(self, filename, content): - self.filename = filename - self.content = content - - def __unicode__(self): - """ - The unicode representation is the filename, so that the pre-database-insertion - logic can use UploadedFile objects - """ - return self.filename - -class FileField(Field): - widget = FileInput - default_error_messages = { - 'invalid': _(u"No file was submitted. Check the encoding type on the form."), - 'missing': _(u"No file was submitted."), - 'empty': _(u"The submitted file is empty."), - } - - def __init__(self, *args, **kwargs): - super(FileField, self).__init__(*args, **kwargs) - - def clean(self, data, initial=None): - super(FileField, self).clean(initial or data) - if not self.required and data in EMPTY_VALUES: - return None - elif not data and initial: - return initial - try: - f = UploadedFile(data['filename'], data['content']) - except TypeError: - raise ValidationError(self.error_messages['invalid']) - except KeyError: - raise ValidationError(self.error_messages['missing']) - if not f.content: - raise ValidationError(self.error_messages['empty']) - return f - -class ImageField(FileField): - default_error_messages = { - 'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."), - } - - def clean(self, data, initial=None): - """ - Checks that the file-upload field data contains a valid image (GIF, JPG, - PNG, possibly others -- whatever the Python Imaging Library supports). - """ - f = super(ImageField, self).clean(data, initial) - if f is None: - return None - elif not data and initial: - return initial - from PIL import Image - from cStringIO import StringIO - try: - # load() is the only method that can spot a truncated JPEG, - # but it cannot be called sanely after verify() - trial_image = Image.open(StringIO(f.content)) - trial_image.load() - # verify() is the only method that can spot a corrupt PNG, - # but it must be called immediately after the constructor - trial_image = Image.open(StringIO(f.content)) - trial_image.verify() - except Exception: # Python Imaging Library doesn't recognize it as an image - raise ValidationError(self.error_messages['invalid_image']) - return f - -url_re = re.compile( - r'^https?://' # http:// or https:// - r'(?:(?:[A-Z0-9-]+\.)+[A-Z]{2,6}|' #domain... - r'localhost|' #localhost... - r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip - r'(?::\d+)?' # optional port - r'(?:/?|/\S+)$', re.IGNORECASE) - -class URLField(RegexField): - default_error_messages = { - 'invalid': _(u'Enter a valid URL.'), - 'invalid_link': _(u'This URL appears to be a broken link.'), - } - - def __init__(self, max_length=None, min_length=None, verify_exists=False, - validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs): - super(URLField, self).__init__(url_re, max_length, min_length, *args, - **kwargs) - self.verify_exists = verify_exists - self.user_agent = validator_user_agent - - def clean(self, value): - # If no URL scheme given, assume http:// - if value and '://' not in value: - value = u'http://%s' % value - value = super(URLField, self).clean(value) - if value == u'': - return value - if self.verify_exists: - import urllib2 - from django.conf import settings - headers = { - "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5", - "Accept-Language": "en-us,en;q=0.5", - "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", - "Connection": "close", - "User-Agent": self.user_agent, - } - try: - req = urllib2.Request(value, None, headers) - u = urllib2.urlopen(req) - except ValueError: - raise ValidationError(self.error_messages['invalid']) - except: # urllib2.URLError, httplib.InvalidURL, etc. - raise ValidationError(self.error_messages['invalid_link']) - return value - -class BooleanField(Field): - widget = CheckboxInput - - def clean(self, value): - """Returns a Python boolean object.""" - super(BooleanField, self).clean(value) - # Explicitly check for the string 'False', which is what a hidden field - # will submit for False. Because bool("True") == True, we don't need to - # handle that explicitly. - if value == 'False': - return False - return bool(value) - -class NullBooleanField(BooleanField): - """ - A field whose valid values are None, True and False. Invalid values are - cleaned to None. - """ - widget = NullBooleanSelect - - def clean(self, value): - return {True: True, False: False}.get(value, None) - -class ChoiceField(Field): - widget = Select - default_error_messages = { - 'invalid_choice': _(u'Select a valid choice. That choice is not one of the available choices.'), - } - - def __init__(self, choices=(), required=True, widget=None, label=None, - initial=None, help_text=None, *args, **kwargs): - super(ChoiceField, self).__init__(required, widget, label, initial, - help_text, *args, **kwargs) - self.choices = choices - - def _get_choices(self): - return self._choices - - def _set_choices(self, value): - # Setting choices also sets the choices on the widget. - # choices can be any iterable, but we call list() on it because - # it will be consumed more than once. - self._choices = self.widget.choices = list(value) - - choices = property(_get_choices, _set_choices) - - def clean(self, value): - """ - Validates that the input is in self.choices. - """ - value = super(ChoiceField, self).clean(value) - if value in EMPTY_VALUES: - value = u'' - value = smart_unicode(value) - if value == u'': - return value - valid_values = set([smart_unicode(k) for k, v in self.choices]) - if value not in valid_values: - raise ValidationError(self.error_messages['invalid_choice'] % {'value': value}) - return value - -class MultipleChoiceField(ChoiceField): - hidden_widget = MultipleHiddenInput - widget = SelectMultiple - default_error_messages = { - 'invalid_choice': _(u'Select a valid choice. %(value)s is not one of the available choices.'), - 'invalid_list': _(u'Enter a list of values.'), - } - - def clean(self, value): - """ - Validates that the input is a list or tuple. - """ - if self.required and not value: - raise ValidationError(self.error_messages['required']) - elif not self.required and not value: - return [] - if not isinstance(value, (list, tuple)): - raise ValidationError(self.error_messages['invalid_list']) - new_value = [smart_unicode(val) for val in value] - # Validate that each value in the value list is in self.choices. - valid_values = set([smart_unicode(k) for k, v in self.choices]) - for val in new_value: - if val not in valid_values: - raise ValidationError(self.error_messages['invalid_choice'] % {'value': val}) - return new_value - -class ComboField(Field): - """ - A Field whose clean() method calls multiple Field clean() methods. - """ - def __init__(self, fields=(), *args, **kwargs): - super(ComboField, self).__init__(*args, **kwargs) - # Set 'required' to False on the individual fields, because the - # required validation will be handled by ComboField, not by those - # individual fields. - for f in fields: - f.required = False - self.fields = fields - - def clean(self, value): - """ - Validates the given value against all of self.fields, which is a - list of Field instances. - """ - super(ComboField, self).clean(value) - for field in self.fields: - value = field.clean(value) - return value - -class MultiValueField(Field): - """ - A Field that aggregates the logic of multiple Fields. - - Its clean() method takes a "decompressed" list of values, which are then - cleaned into a single value according to self.fields. Each value in - this list is cleaned by the corresponding field -- the first value is - cleaned by the first field, the second value is cleaned by the second - field, etc. Once all fields are cleaned, the list of clean values is - "compressed" into a single value. - - Subclasses should not have to implement clean(). Instead, they must - implement compress(), which takes a list of valid values and returns a - "compressed" version of those values -- a single value. - - You'll probably want to use this with MultiWidget. - """ - default_error_messages = { - 'invalid': _(u'Enter a list of values.'), - } - - def __init__(self, fields=(), *args, **kwargs): - super(MultiValueField, self).__init__(*args, **kwargs) - # Set 'required' to False on the individual fields, because the - # required validation will be handled by MultiValueField, not by those - # individual fields. - for f in fields: - f.required = False - self.fields = fields - - def clean(self, value): - """ - Validates every value in the given list. A value is validated against - the corresponding Field in self.fields. - - For example, if this MultiValueField was instantiated with - fields=(DateField(), TimeField()), clean() would call - DateField.clean(value[0]) and TimeField.clean(value[1]). - """ - cleaned_data = [] - errors = ErrorList() - if not value or isinstance(value, (list, tuple)): - if not value or not [v for v in value if v not in EMPTY_VALUES]: - if self.required: - raise ValidationError(self.error_messages['required']) - else: - return self.compress([]) - else: - raise ValidationError(self.error_messages['invalid']) - for i, field in enumerate(self.fields): - try: - field_value = value[i] - except IndexError: - field_value = None - if self.required and field_value in EMPTY_VALUES: - raise ValidationError(self.error_messages['required']) - try: - cleaned_data.append(field.clean(field_value)) - except ValidationError, e: - # Collect all validation errors in a single list, which we'll - # raise at the end of clean(), rather than raising a single - # exception for the first error we encounter. - errors.extend(e.messages) - if errors: - raise ValidationError(errors) - return self.compress(cleaned_data) - - def compress(self, data_list): - """ - Returns a single value for the given list of values. The values can be - assumed to be valid. - - For example, if this MultiValueField was instantiated with - fields=(DateField(), TimeField()), this might return a datetime - object created by combining the date and time in data_list. - """ - raise NotImplementedError('Subclasses must implement this method.') - -class FilePathField(ChoiceField): - def __init__(self, path, match=None, recursive=False, required=True, - widget=Select, label=None, initial=None, help_text=None, - *args, **kwargs): - self.path, self.match, self.recursive = path, match, recursive - super(FilePathField, self).__init__(choices=(), required=required, - widget=widget, label=label, initial=initial, help_text=help_text, - *args, **kwargs) - self.choices = [] - if self.match is not None: - self.match_re = re.compile(self.match) - if recursive: - for root, dirs, files in os.walk(self.path): - for f in files: - if self.match is None or self.match_re.search(f): - f = os.path.join(root, f) - self.choices.append((f, f.replace(path, "", 1))) - else: - try: - for f in os.listdir(self.path): - full_file = os.path.join(self.path, f) - if os.path.isfile(full_file) and (self.match is None or self.match_re.search(f)): - self.choices.append((full_file, f)) - except OSError: - pass - self.widget.choices = self.choices - -class SplitDateTimeField(MultiValueField): - default_error_messages = { - 'invalid_date': _(u'Enter a valid date.'), - 'invalid_time': _(u'Enter a valid time.'), - } - - def __init__(self, *args, **kwargs): - errors = self.default_error_messages.copy() - if 'error_messages' in kwargs: - errors.update(kwargs['error_messages']) - fields = ( - DateField(error_messages={'invalid': errors['invalid_date']}), - TimeField(error_messages={'invalid': errors['invalid_time']}), - ) - super(SplitDateTimeField, self).__init__(fields, *args, **kwargs) - - def compress(self, data_list): - if data_list: - # Raise a validation error if time or date is empty - # (possible if SplitDateTimeField has required=False). - if data_list[0] in EMPTY_VALUES: - raise ValidationError(self.error_messages['invalid_date']) - if data_list[1] in EMPTY_VALUES: - raise ValidationError(self.error_messages['invalid_time']) - return datetime.datetime.combine(*data_list) - return None - -ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') - -class IPAddressField(RegexField): - default_error_messages = { - 'invalid': _(u'Enter a valid IPv4 address.'), - } - - def __init__(self, *args, **kwargs): - super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs) diff --git a/deluge/ui/webui/lib/newforms_portable/forms.py b/deluge/ui/webui/lib/newforms_portable/forms.py deleted file mode 100644 index 2c481e47a..000000000 --- a/deluge/ui/webui/lib/newforms_portable/forms.py +++ /dev/null @@ -1,350 +0,0 @@ -""" -Form classes -""" - -from copy import deepcopy - -from django.utils.datastructures import SortedDict -from django.utils.html import escape -from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode -from django.utils.safestring import mark_safe - -from fields import Field, FileField -from widgets import TextInput, Textarea -from util import flatatt, ErrorDict, ErrorList, ValidationError - -__all__ = ('BaseForm', 'Form') - -NON_FIELD_ERRORS = '__all__' - -def pretty_name(name): - "Converts 'first_name' to 'First name'" - name = name[0].upper() + name[1:] - return name.replace('_', ' ') - -def get_declared_fields(bases, attrs, with_base_fields=True): - """ - Create a list of form field instances from the passed in 'attrs', plus any - similar fields on the base classes (in 'bases'). This is used by both the - Form and ModelForm metclasses. - - If 'with_base_fields' is True, all fields from the bases are used. - Otherwise, only fields in the 'declared_fields' attribute on the bases are - used. The distinction is useful in ModelForm subclassing. - """ - fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)] - fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter)) - - # If this class is subclassing another Form, add that Form's fields. - # Note that we loop over the bases in *reverse*. This is necessary in - # order to preserve the correct order of fields. - if with_base_fields: - for base in bases[::-1]: - if hasattr(base, 'base_fields'): - fields = base.base_fields.items() + fields - else: - for base in bases[::-1]: - if hasattr(base, 'declared_fields'): - fields = base.declared_fields.items() + fields - - return SortedDict(fields) - -class DeclarativeFieldsMetaclass(type): - """ - Metaclass that converts Field attributes to a dictionary called - 'base_fields', taking into account parent class 'base_fields' as well. - """ - def __new__(cls, name, bases, attrs): - attrs['base_fields'] = get_declared_fields(bases, attrs) - return type.__new__(cls, name, bases, attrs) - -class BaseForm(StrAndUnicode): - # This is the main implementation of all the Form logic. Note that this - # class is different than Form. See the comments by the Form class for more - # information. Any improvements to the form API should be made to *this* - # class, not to the Form class. - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - initial=None, error_class=ErrorList, label_suffix=':'): - self.is_bound = data is not None or files is not None - self.data = data or {} - self.files = files or {} - self.auto_id = auto_id - self.prefix = prefix - self.initial = initial or {} - self.error_class = error_class - self.label_suffix = label_suffix - self._errors = None # Stores the errors after clean() has been called. - - # The base_fields class attribute is the *class-wide* definition of - # fields. Because a particular *instance* of the class might want to - # alter self.fields, we create self.fields here by copying base_fields. - # Instances should always modify self.fields; they should not modify - # self.base_fields. - self.fields = deepcopy(self.base_fields) - - def __unicode__(self): - return self.as_table() - - def __iter__(self): - for name, field in self.fields.items(): - yield BoundField(self, field, name) - - def __getitem__(self, name): - "Returns a BoundField with the given name." - try: - field = self.fields[name] - except KeyError: - raise KeyError('Key %r not found in Form' % name) - return BoundField(self, field, name) - - def _get_errors(self): - "Returns an ErrorDict for the data provided for the form" - if self._errors is None: - self.full_clean() - return self._errors - errors = property(_get_errors) - - def is_valid(self): - """ - Returns True if the form has no errors. Otherwise, False. If errors are - being ignored, returns False. - """ - return self.is_bound and not bool(self.errors) - - def add_prefix(self, field_name): - """ - Returns the field name with a prefix appended, if this Form has a - prefix set. - - Subclasses may wish to override. - """ - return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name - - def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row): - "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()." - top_errors = self.non_field_errors() # Errors that should be displayed above all fields. - output, hidden_fields = [], [] - for name, field in self.fields.items(): - bf = BoundField(self, field, name) - bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable. - if bf.is_hidden: - if bf_errors: - top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors]) - hidden_fields.append(unicode(bf)) - else: - if errors_on_separate_row and bf_errors: - output.append(error_row % force_unicode(bf_errors)) - if bf.label: - label = escape(force_unicode(bf.label)) - # Only add the suffix if the label does not end in - # punctuation. - if self.label_suffix: - if label[-1] not in ':?.!': - label += self.label_suffix - label = bf.label_tag(label) or '' - else: - label = '' - if field.help_text: - help_text = help_text_html % force_unicode(field.help_text) - else: - help_text = u'' - output.append(normal_row % {'errors': force_unicode(bf_errors), 'label': force_unicode(label), 'field': unicode(bf), 'help_text': help_text}) - if top_errors: - output.insert(0, error_row % force_unicode(top_errors)) - if hidden_fields: # Insert any hidden fields in the last row. - str_hidden = u''.join(hidden_fields) - if output: - last_row = output[-1] - # Chop off the trailing row_ender (e.g. '') and - # insert the hidden fields. - output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender - else: - # If there aren't any rows in the output, just append the - # hidden fields. - output.append(str_hidden) - return mark_safe(u'\n'.join(output)) - - def as_table(self): - "Returns this form rendered as HTML
s." - return self._html_output(u'
%(label)s %(field)s%(help_text)s
', u'%s', '', u' %s', True) - - def non_field_errors(self): - """ - Returns an ErrorList of errors that aren't associated with a particular - field -- i.e., from Form.clean(). Returns an empty ErrorList if there - are none. - """ - return self.errors.get(NON_FIELD_ERRORS, self.error_class()) - - def full_clean(self): - """ - Cleans all of self.data and populates self._errors and - self.cleaned_data. - """ - self._errors = ErrorDict() - if not self.is_bound: # Stop further processing. - return - self.cleaned_data = {} - for name, field in self.fields.items(): - # value_from_datadict() gets the data from the data dictionaries. - # Each widget type knows how to retrieve its own data, because some - # widgets split data over several HTML fields. - value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) - try: - if isinstance(field, FileField): - initial = self.initial.get(name, field.initial) - value = field.clean(value, initial) - else: - value = field.clean(value) - self.cleaned_data[name] = value - if hasattr(self, 'clean_%s' % name): - value = getattr(self, 'clean_%s' % name)() - self.cleaned_data[name] = value - except ValidationError, e: - self._errors[name] = e.messages - if name in self.cleaned_data: - del self.cleaned_data[name] - try: - self.cleaned_data = self.clean() - except ValidationError, e: - self._errors[NON_FIELD_ERRORS] = e.messages - if self._errors: - delattr(self, 'cleaned_data') - - def clean(self): - """ - Hook for doing any extra form-wide cleaning after Field.clean() been - called on every field. Any ValidationError raised by this method will - not be associated with a particular field; it will have a special-case - association with the field named '__all__'. - """ - return self.cleaned_data - - def is_multipart(self): - """ - Returns True if the form needs to be multipart-encrypted, i.e. it has - FileInput. Otherwise, False. - """ - for field in self.fields.values(): - if field.widget.needs_multipart_form: - return True - return False - -class Form(BaseForm): - "A collection of Fields, plus their associated data." - # This is a separate class from BaseForm in order to abstract the way - # self.fields is specified. This class (Form) is the one that does the - # fancy metaclass stuff purely for the semantic sugar -- it allows one - # to define a form using declarative syntax. - # BaseForm itself has no way of designating self.fields. - __metaclass__ = DeclarativeFieldsMetaclass - -class BoundField(StrAndUnicode): - "A Field plus data" - def __init__(self, form, field, name): - self.form = form - self.field = field - self.name = name - self.html_name = form.add_prefix(name) - if self.field.label is None: - self.label = pretty_name(name) - else: - self.label = self.field.label - self.help_text = field.help_text or '' - - def __unicode__(self): - """Renders this field as an HTML widget.""" - return self.as_widget() - - def _errors(self): - """ - Returns an ErrorList for this field. Returns an empty ErrorList - if there are none. - """ - return self.form.errors.get(self.name, self.form.error_class()) - errors = property(_errors) - - def as_widget(self, widget=None, attrs=None): - """ - Renders the field by rendering the passed widget, adding any HTML - attributes passed as attrs. If no widget is specified, then the - field's default widget will be used. - """ - if not widget: - widget = self.field.widget - attrs = attrs or {} - auto_id = self.auto_id - if auto_id and 'id' not in attrs and 'id' not in widget.attrs: - attrs['id'] = auto_id - if not self.form.is_bound: - data = self.form.initial.get(self.name, self.field.initial) - if callable(data): - data = data() - else: - data = self.data - return widget.render(self.html_name, data, attrs=attrs) - - def as_text(self, attrs=None): - """ - Returns a string of HTML for representing this as an . - """ - return self.as_widget(TextInput(), attrs) - - def as_textarea(self, attrs=None): - "Returns a string of HTML for representing this as a