r771 - in python-clientform/trunk: . ClientForm.egg-info debian
Jérémy Bobbio
lunar at alioth.debian.org
Mon Apr 9 22:05:00 UTC 2007
Author: lunar
Date: 2007-04-09 22:04:59 +0000 (Mon, 09 Apr 2007)
New Revision: 771
Added:
python-clientform/trunk/ClientForm.egg-info/dependency_links.txt
python-clientform/trunk/ez_setup.py
python-clientform/trunk/setup.cfg
Removed:
python-clientform/trunk/ez_setup/
Modified:
python-clientform/trunk/ChangeLog.txt
python-clientform/trunk/ClientForm.egg-info/PKG-INFO
python-clientform/trunk/ClientForm.egg-info/SOURCES.txt
python-clientform/trunk/ClientForm.egg-info/zip-safe
python-clientform/trunk/ClientForm.py
python-clientform/trunk/GeneralFAQ.html
python-clientform/trunk/INSTALL.txt
python-clientform/trunk/MANIFEST.in
python-clientform/trunk/PKG-INFO
python-clientform/trunk/README.html
python-clientform/trunk/README.html.in
python-clientform/trunk/README.txt
python-clientform/trunk/debian/changelog
python-clientform/trunk/debian/control
python-clientform/trunk/setup.py
python-clientform/trunk/test.py
Log:
Ready 0.2.6-1.
Modified: python-clientform/trunk/ChangeLog.txt
===================================================================
--- python-clientform/trunk/ChangeLog.txt 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/ChangeLog.txt 2007-04-09 22:04:59 UTC (rev 771)
@@ -1,6 +1,49 @@
This isn't really in proper GNU ChangeLog format, it just happens to
look that way.
+2007-01-07 John J Lee <jjl at pobox.com>
+ * 0.2.6 release:
+ * Don't allow underlying parser errors (e.g. SGMLParseError)
+ through -- always raise ClientForm.ParseError . To preserve.
+ However, any code that distinguishes between
+ ClientForm.ParseError and these other exceptions will break.
+ * Allow controls to appear outside of forms (the HTML spec allows
+ this). This involved adding new functions ParseFileEx and
+ ParseResponseEx, which return a list that's always one longer
+ than the return value of their counterparts ParseFile and
+ ParseResponse. The new first element in the list of forms is an
+ HTMLForm representing the collection of all forms that lie
+ outside of any FORM element.
+
+2006-10-24 John J Lee <jjl at pobox.com>
+ * 0.2.5 release:
+ * Fix fragment bug introduced in 0.2.4 (thanks Dave Marble). This
+ only caused a bug when used with mechanize: it does not affect
+ users using ClientForm without mechanize.
+
+2006-10-14 John J Lee <jjl at pobox.com>
+ * 0.2.4 release:
+ * Support for mechanize 0.1.4b.
+
+2006-10-12 John J Lee <jjl at pobox.com>
+ * 0.2.3 release:
+ * Fix entity reference / character reference handling for
+ Python 2.5 .
+ * Nameless list controls are now never successful.
+ * List controls used to get inappropriately .merge_control()ed
+ with other controls, or parsing would raise AmbiguityError.
+ That's fixed now.
+ * Handle line endings in element content the same way browsers do
+ (strip exactly one leading linebreaks, if any leading linebreaks
+ are present) (patch from Benji York).
+ * Convert TEXTAREA content to DOS line ending convention, again
+ following the major browsers.
+ * Allow mechanize to supply URL join / parse / unparse functions,
+ to allow mechanize to follow RFC 3986, thus fixing some URL
+ processing bugs. ClientForm should do the same; probably I
+ should merge the two projects after final mechanize release.
+ * Doc fixes.
+
2006-03-22 John J Lee <jjl at pobox.com>
* 0.2.2 release:
* Stop trying to record precise dates in changelog, since that's
Modified: python-clientform/trunk/ClientForm.egg-info/PKG-INFO
===================================================================
--- python-clientform/trunk/ClientForm.egg-info/PKG-INFO 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/ClientForm.egg-info/PKG-INFO 2007-04-09 22:04:59 UTC (rev 771)
@@ -1,12 +1,12 @@
Metadata-Version: 1.0
Name: ClientForm
-Version: 0.2.2
+Version: 0.2.6
Summary: Client-side HTML form handling.
Home-page: http://wwwsearch.sourceforge.net/ClientForm/
Author: John J. Lee
Author-email: jjl at pobox.com
License: BSD
-Download-URL: http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0.2.2.tar.gz
+Download-URL: http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0.2.6.tar.gz
Description: ClientForm is a Python module for handling HTML forms on the client
side, useful for parsing HTML forms, filling them in and returning the
completed forms to the server. It developed from a port of Gisle Aas'
Modified: python-clientform/trunk/ClientForm.egg-info/SOURCES.txt
===================================================================
--- python-clientform/trunk/ClientForm.egg-info/SOURCES.txt 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/ClientForm.egg-info/SOURCES.txt 2007-04-09 22:04:59 UTC (rev 771)
@@ -8,10 +8,12 @@
README.html
README.html.in
README.txt
+ez_setup.py
setup.py
test.py
ClientForm.egg-info/PKG-INFO
ClientForm.egg-info/SOURCES.txt
+ClientForm.egg-info/dependency_links.txt
ClientForm.egg-info/top_level.txt
ClientForm.egg-info/zip-safe
examples/data.dat
@@ -20,8 +22,6 @@
examples/example.html
examples/example.py
examples/simple.py
-ez_setup/README.txt
-ez_setup/__init__.py
testdata/Auth.html
testdata/FullSearch.html
testdata/GeneralSearch.html
Copied: python-clientform/trunk/ClientForm.egg-info/dependency_links.txt (from rev 770, python-clientform/branches/upstream/current/ClientForm.egg-info/dependency_links.txt)
Modified: python-clientform/trunk/ClientForm.egg-info/zip-safe
===================================================================
--- python-clientform/trunk/ClientForm.egg-info/zip-safe 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/ClientForm.egg-info/zip-safe 2007-04-09 22:04:59 UTC (rev 771)
@@ -0,0 +1 @@
+
Modified: python-clientform/trunk/ClientForm.py
===================================================================
--- python-clientform/trunk/ClientForm.py 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/ClientForm.py 2007-04-09 22:04:59 UTC (rev 771)
@@ -21,18 +21,15 @@
Copyright 1998-2000 Gisle Aas.
This code is free software; you can redistribute it and/or modify it
-under the terms of the BSD License (see the file COPYING included with
-the distribution).
+under the terms of the BSD or ZPL 2.1 licenses (see the file
+COPYING.txt included with the distribution).
"""
# XXX
-# Remove unescape_attr method
+# add an __all__
# Remove parser testing hack
# safeUrl()-ize action
-# Really should to merge CC, CF, pp and mechanize as soon as mechanize
-# goes to beta...
-# Add url attribute to ParseError
# Switch to unicode throughout (would be 0.3.x)
# See Wichert Akkerman's 2004-01-22 message to c.l.py.
# Add charset parameter to Content-type headers? How to find value??
@@ -41,11 +38,6 @@
# Does file upload work when name is missing? Sourceforge tracker form
# doesn't like it. Check standards, and test with Apache. Test
# binary upload with Apache.
-# Controls can have name=None (e.g. forms constructed partly with
-# JavaScript), but find_control can't be told to find a control
-# with that name, because None there means 'unspecified'. Can still
-# get at by nr, but would be nice to be able to specify something
-# equivalent to name=None, too.
# mailto submission & enctype text/plain
# I'm not going to fix this unless somebody tells me what real servers
# that want this encoding actually expect: If enctype is
@@ -109,10 +101,22 @@
import sys, urllib, urllib2, types, mimetools, copy, urlparse, \
htmlentitydefs, re, random
-from urlparse import urljoin
from cStringIO import StringIO
+import sgmllib
+# monkeypatch to fix http://www.python.org/sf/803422 :-(
+sgmllib.charref = re.compile("&#(x?[0-9a-fA-F]+)[^0-9a-fA-F]")
+
+# HTMLParser.HTMLParser is recent, so live without it if it's not available
+# (also, sgmllib.SGMLParser is much more tolerant of bad HTML)
try:
+ import HTMLParser
+except ImportError:
+ HAVE_MODULE_HTMLPARSER = False
+else:
+ HAVE_MODULE_HTMLPARSER = True
+
+try:
import warnings
except ImportError:
def deprecation(message):
@@ -121,15 +125,21 @@
def deprecation(message):
warnings.warn(message, DeprecationWarning, stacklevel=2)
-VERSION = "0.2.2"
+VERSION = "0.2.6"
CHUNK = 1024 # size of chunks fed to parser, in bytes
DEFAULT_ENCODING = "latin-1"
+class Missing: pass
+
_compress_re = re.compile(r"\s+")
def compress_text(text): return _compress_re.sub(" ", text.strip())
+def normalize_line_endings(text):
+ return re.sub(r"(?:(?<!\r)\n)|(?:\r(?!\n))", "\r\n", text)
+
+
# This version of urlencode is from my Python 1.5.2 back-port of the
# Python 2.1 CVS maintenance branch of urllib. It will accept a sequence
# of pairs instead of a mapping -- the 2.0 version only accepts a mapping.
@@ -429,10 +439,25 @@
class ItemCountError(ValueError): pass
+# for backwards compatibility, ParseError derives from exceptions that were
+# raised by versions of ClientForm <= 0.2.5
+if HAVE_MODULE_HTMLPARSER:
+ SGMLLIB_PARSEERROR = sgmllib.SGMLParseError
+ class ParseError(sgmllib.SGMLParseError,
+ HTMLParser.HTMLParseError,
+ ):
+ pass
+else:
+ if hasattr(sgmllib, "SGMLParseError"):
+ SGMLLIB_PARSEERROR = sgmllib.SGMLParseError
+ class ParseError(sgmllib.SGMLParseError):
+ pass
+ else:
+ SGMLLIB_PARSEERROR = RuntimeError
+ class ParseError(RuntimeError):
+ pass
-class ParseError(Exception): pass
-
class _AbstractFormParser:
"""forms attribute contains HTMLForm instances on completion."""
# thanks to Moshe Zadka for an example of sgmllib/htmllib usage
@@ -452,6 +477,13 @@
self._option = None
self._textarea = None
+ # forms[0] will contain all controls that are outside of any form
+ # self._global_form is an alias for self.forms[0]
+ self._global_form = None
+ self.start_form([])
+ self.end_form()
+ self._current_form = self._global_form = self.forms[0]
+
def do_base(self, attrs):
debug("%s", attrs)
for key, value in attrs:
@@ -462,12 +494,12 @@
debug("")
if self._current_label is not None:
self.end_label()
- if self._current_form is not None:
+ if self._current_form is not self._global_form:
self.end_form()
def start_form(self, attrs):
debug("%s", attrs)
- if self._current_form is not None:
+ if self._current_form is not self._global_form:
raise ParseError("nested FORMs")
name = None
action = None
@@ -491,15 +523,13 @@
debug("")
if self._current_label is not None:
self.end_label()
- if self._current_form is None:
+ if self._current_form is self._global_form:
raise ParseError("end of FORM before start")
self.forms.append(self._current_form)
- self._current_form = None
+ self._current_form = self._global_form
def start_select(self, attrs):
debug("%s", attrs)
- if self._current_form is None:
- raise ParseError("start of SELECT before start of FORM")
if self._select is not None:
raise ParseError("nested SELECTs")
if self._textarea is not None:
@@ -515,8 +545,8 @@
def end_select(self):
debug("")
- if self._current_form is None:
- raise ParseError("end of SELECT before start of FORM")
+ if self._current_form is self._global_form:
+ return
if self._select is None:
raise ParseError("end of SELECT before start")
@@ -583,8 +613,6 @@
def start_textarea(self, attrs):
debug("%s", attrs)
- if self._current_form is None:
- raise ParseError("start of TEXTAREA before start of FORM")
if self._textarea is not None:
raise ParseError("nested TEXTAREAs")
if self._select is not None:
@@ -598,8 +626,8 @@
def end_textarea(self):
debug("")
- if self._current_form is None:
- raise ParseError("end of TEXTAREA before start of FORM")
+ if self._current_form is self._global_form:
+ return
if self._textarea is None:
raise ParseError("end of TEXTAREA before start")
controls = self._current_form[2]
@@ -642,14 +670,17 @@
d["__label"] = self._current_label
def handle_data(self, data):
+ debug("%s", data)
+
# according to http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.1
# line break immediately after start tags or immediately before end
# tags must be ignored, but real browsers only ignore a line break
# after a start tag, so we'll do that.
- if data[0:1] == '\n':
+ if data[0:2] == "\r\n":
+ data = data[2:]
+ if data[0:1] in ["\n", "\r"]:
data = data[1:]
- debug("%s", data)
if self._option is not None:
# self._option is a dictionary of the OPTION element's HTML
# attributes, but it has two special keys, one of which is the
@@ -660,6 +691,7 @@
elif self._textarea is not None:
map = self._textarea
key = "value"
+ data = normalize_line_endings(data)
# not if within option or textarea
elif self._current_label is not None:
map = self._current_label
@@ -674,8 +706,6 @@
def do_button(self, attrs):
debug("%s", attrs)
- if self._current_form is None:
- raise ParseError("start of BUTTON before start of FORM")
d = {}
d["type"] = "submit" # default
for key, val in attrs:
@@ -694,8 +724,6 @@
def do_input(self, attrs):
debug("%s", attrs)
- if self._current_form is None:
- raise ParseError("start of INPUT before start of FORM")
d = {}
d["type"] = "text" # default
for key, val in attrs:
@@ -709,8 +737,6 @@
def do_isindex(self, attrs):
debug("%s", attrs)
- if self._current_form is None:
- raise ParseError("start of ISINDEX before start of FORM")
d = {}
for key, val in attrs:
d[key] = val
@@ -750,11 +776,7 @@
def unknown_charref(self, ref): self.handle_data("&#%s;" % ref)
-# HTMLParser.HTMLParser is recent, so live without it if it's not available
-# (also, htmllib.HTMLParser is much more tolerant of bad HTML)
-try:
- import HTMLParser
-except ImportError:
+if not HAVE_MODULE_HTMLPARSER:
class XHTMLCompatibleFormParser:
def __init__(self, entitydefs=None, encoding=DEFAULT_ENCODING):
raise ValueError("HTMLParser could not be imported")
@@ -766,6 +788,12 @@
HTMLParser.HTMLParser.__init__(self)
_AbstractFormParser.__init__(self, entitydefs, encoding)
+ def feed(self, data):
+ try:
+ HTMLParser.HTMLParser.feed(self, data)
+ except HTMLParser.HTMLParseError, exc:
+ raise ParseError(exc)
+
def start_option(self, attrs):
_AbstractFormParser._start_option(self, attrs)
@@ -803,31 +831,52 @@
def unescape_attrs_if_required(self, attrs):
return attrs # ditto
-import sgmllib
-# monkeypatch to fix http://www.python.org/sf/803422 :-(
-sgmllib.charref = re.compile("&#(x?[0-9a-fA-F]+)[^0-9a-fA-F]")
+
class _AbstractSgmllibParser(_AbstractFormParser):
+
def do_option(self, attrs):
_AbstractFormParser._start_option(self, attrs)
- def unescape_attr_if_required(self, name):
- return self.unescape_attr(name)
- def unescape_attrs_if_required(self, attrs):
- return self.unescape_attrs(attrs)
+ if sys.version_info[:2] >= (2,5):
+ # we override this attr to decode hex charrefs
+ entity_or_charref = re.compile(
+ '&(?:([a-zA-Z][-.a-zA-Z0-9]*)|#(x?[0-9a-fA-F]+))(;?)')
+ def convert_entityref(self, name):
+ return unescape("&%s;" % name, self._entitydefs, self._encoding)
+ def convert_charref(self, name):
+ return unescape_charref("%s" % name, self._encoding)
+ def unescape_attr_if_required(self, name):
+ return name # sgmllib already did it
+ def unescape_attrs_if_required(self, attrs):
+ return attrs # ditto
+ else:
+ def unescape_attr_if_required(self, name):
+ return self.unescape_attr(name)
+ def unescape_attrs_if_required(self, attrs):
+ return self.unescape_attrs(attrs)
+
class FormParser(_AbstractSgmllibParser, sgmllib.SGMLParser):
"""Good for tolerance of incorrect HTML, bad for XHTML."""
def __init__(self, entitydefs=None, encoding=DEFAULT_ENCODING):
sgmllib.SGMLParser.__init__(self)
_AbstractFormParser.__init__(self, entitydefs, encoding)
-try:
- if sys.version_info[:2] < (2, 2):
- raise ImportError # BeautifulSoup uses generators
- import BeautifulSoup
-except ImportError:
- pass
-else:
+ def feed(self, data):
+ try:
+ sgmllib.SGMLParser.feed(self, data)
+ except SGMLLIB_PARSEERROR, exc:
+ raise ParseError(exc)
+
+
+
+# sigh, must support mechanize by allowing dynamic creation of classes based on
+# its bundled copy of BeautifulSoup (which was necessary because of dependency
+# problems)
+
+def _create_bs_classes(bs,
+ icbinbs,
+ ):
class _AbstractBSFormParser(_AbstractSgmllibParser):
bs_base_class = None
def __init__(self, entitydefs=None, encoding=DEFAULT_ENCODING):
@@ -836,31 +885,114 @@
def handle_data(self, data):
_AbstractFormParser.handle_data(self, data)
self.bs_base_class.handle_data(self, data)
+ def feed(self, data):
+ try:
+ self.bs_base_class.feed(self, data)
+ except SGMLLIB_PARSEERROR, exc:
+ raise ParseError(exc)
- class RobustFormParser(_AbstractBSFormParser, BeautifulSoup.BeautifulSoup):
+
+ class RobustFormParser(_AbstractBSFormParser, bs):
"""Tries to be highly tolerant of incorrect HTML."""
- bs_base_class = BeautifulSoup.BeautifulSoup
- class NestingRobustFormParser(_AbstractBSFormParser,
- BeautifulSoup.ICantBelieveItsBeautifulSoup):
+ pass
+ RobustFormParser.bs_base_class = bs
+ class NestingRobustFormParser(_AbstractBSFormParser, icbinbs):
"""Tries to be highly tolerant of incorrect HTML.
Different from RobustFormParser in that it more often guesses nesting
above missing end tags (see BeautifulSoup docs).
"""
- bs_base_class = BeautifulSoup.ICantBelieveItsBeautifulSoup
+ pass
+ NestingRobustFormParser.bs_base_class = icbinbs
+ return RobustFormParser, NestingRobustFormParser
+
+try:
+ if sys.version_info[:2] < (2, 2):
+ raise ImportError # BeautifulSoup uses generators
+ import BeautifulSoup
+except ImportError:
+ pass
+else:
+ RobustFormParser, NestingRobustFormParser = _create_bs_classes(
+ BeautifulSoup.BeautifulSoup, BeautifulSoup.ICantBelieveItsBeautifulSoup
+ )
+
+
#FormParser = XHTMLCompatibleFormParser # testing hack
#FormParser = RobustFormParser # testing hack
-def ParseResponse(response, select_default=False,
- ignore_errors=False, # ignored!
- form_parser_class=FormParser,
- request_class=urllib2.Request,
- entitydefs=None,
- backwards_compat=True,
- encoding=DEFAULT_ENCODING,
- ):
+
+def ParseResponseEx(response,
+ select_default=False,
+ form_parser_class=FormParser,
+ request_class=urllib2.Request,
+ entitydefs=None,
+ encoding=DEFAULT_ENCODING,
+
+ # private
+ _urljoin=urlparse.urljoin,
+ _urlparse=urlparse.urlparse,
+ _urlunparse=urlparse.urlunparse,
+ ):
+ """Identical to ParseResponse, except that:
+
+ 1. The returned list contains an extra item. The first form in the list
+ contains all controls not contained in any FORM element.
+
+ 2. The arguments ignore_errors and backwards_compat have been removed.
+
+ 3. Backwards-compatibility mode (backwards_compat=True) is not available.
+ """
+ return _ParseFileEx(response, response.geturl(),
+ select_default,
+ False,
+ form_parser_class,
+ request_class,
+ entitydefs,
+ False,
+ encoding,
+ _urljoin=_urljoin,
+ _urlparse=_urlparse,
+ _urlunparse=_urlunparse,
+ )
+
+def ParseFileEx(file, base_uri,
+ select_default=False,
+ form_parser_class=FormParser,
+ request_class=urllib2.Request,
+ entitydefs=None,
+ encoding=DEFAULT_ENCODING,
+
+ # private
+ _urljoin=urlparse.urljoin,
+ _urlparse=urlparse.urlparse,
+ _urlunparse=urlparse.urlunparse,
+ ):
+ """Identical to ParseFile, except that:
+
+ 1. The returned list contains an extra item. The first form in the list
+ contains all controls not contained in any FORM element.
+
+ 2. The arguments ignore_errors and backwards_compat have been removed.
+
+ 3. Backwards-compatibility mode (backwards_compat=True) is not available.
+ """
+ return _ParseFileEx(file, base_uri,
+ select_default,
+ False,
+ form_parser_class,
+ request_class,
+ entitydefs,
+ False,
+ encoding,
+ _urljoin=_urljoin,
+ _urlparse=_urlparse,
+ _urlunparse=_urlunparse,
+ )
+
+def ParseResponse(response, *args, **kwds):
"""Parse HTTP response and return a list of HTMLForm instances.
The return value of urllib2.urlopen can be conveniently passed to this
@@ -920,23 +1052,9 @@
own risk: there is no well-defined interface.
"""
- return ParseFile(response, response.geturl(), select_default,
- False,
- form_parser_class,
- request_class,
- entitydefs,
- backwards_compat,
- encoding,
- )
+ return _ParseFileEx(response, response.geturl(), *args, **kwds)[1:]
-def ParseFile(file, base_uri, select_default=False,
- ignore_errors=False, # ignored!
- form_parser_class=FormParser,
- request_class=urllib2.Request,
- entitydefs=None,
- backwards_compat=True,
- encoding=DEFAULT_ENCODING,
- ):
+def ParseFile(file, base_uri, *args, **kwds):
"""Parse HTML and return a list of HTMLForm instances.
ClientForm.ParseError is raised on parse errors.
@@ -950,6 +1068,20 @@
For the other arguments and further details, see ParseResponse.__doc__.
"""
+ return _ParseFileEx(file, base_uri, *args, **kwds)[1:]
+
+def _ParseFileEx(file, base_uri,
+ select_default=False,
+ ignore_errors=False,
+ form_parser_class=FormParser,
+ request_class=urllib2.Request,
+ entitydefs=None,
+ backwards_compat=True,
+ encoding=DEFAULT_ENCODING,
+ _urljoin=urlparse.urljoin,
+ _urlparse=urlparse.urlparse,
+ _urlunparse=urlparse.urlunparse,
+ ):
if backwards_compat:
deprecation("operating in backwards-compatibility mode")
fp = form_parser_class(entitydefs, encoding)
@@ -980,7 +1112,7 @@
if action is None:
action = base_uri
else:
- action = urljoin(base_uri, action)
+ action = _urljoin(base_uri, action)
action = fp.unescape_attr_if_required(action)
name = fp.unescape_attr_if_required(name)
attrs = fp.unescape_attrs_if_required(attrs)
@@ -988,6 +1120,8 @@
form = HTMLForm(
action, method, enctype, name, attrs, request_class,
forms, labels, id_to_labels, backwards_compat)
+ form._urlparse = _urlparse
+ form._urlunparse = _urlunparse
for ii in range(len(controls)):
type, name, attrs = controls[ii]
attrs = fp.unescape_attrs_if_required(attrs)
@@ -1181,6 +1315,9 @@
self._clicked = False
+ self._urlparse = urlparse.urlparse
+ self._urlunparse = urlparse.urlunparse
+
def __getattr__(self, name):
if name == "value":
return self.__dict__["_value"]
@@ -1389,10 +1526,10 @@
# This doesn't seem to be specified in HTML 4.01 spec. (ISINDEX is
# deprecated in 4.01, but it should still say how to submit it).
# Submission of ISINDEX is explained in the HTML 3.2 spec, though.
- parts = urlparse.urlparse(form.action)
+ parts = self._urlparse(form.action)
rest, (query, frag) = parts[:-2], parts[-2:]
- parts = rest + (urllib.quote_plus(self.value), "")
- url = urlparse.urlunparse(parts)
+ parts = rest + (urllib.quote_plus(self.value), None)
+ url = self._urlunparse(parts)
req_data = url, None, []
if return_type == "pairs":
@@ -1860,12 +1997,16 @@
assert self._form is None or form == self._form, (
"can't add control to more than one form")
self._form = form
- try:
- control = form.find_control(self.name, self.type)
- except ControlNotFoundError:
+ if self.name is None:
+ # always count nameless elements as separate controls
Control.add_to_form(self, form)
else:
- control.merge_control(self)
+ try:
+ control = form.find_control(self.name, self.type)
+ except (ControlNotFoundError, AmbiguityError):
+ Control.add_to_form(self, form)
+ else:
+ control.merge_control(self)
def merge_control(self, control):
assert bool(control.multiple) == bool(self.multiple)
@@ -1911,6 +2052,8 @@
def __getattr__(self, name):
if name == "value":
compat = self._form.backwards_compat
+ if self.name is None:
+ return []
return [o.name for o in self.items if o.selected and
(not o.disabled or compat)]
else:
@@ -2080,7 +2223,7 @@
return [o.name for o in self.items]
def _totally_ordered_pairs(self):
- if self.disabled:
+ if self.disabled or self.name is None:
return []
else:
return [(o._index, self.name, o.name) for o in self.items
@@ -2622,6 +2765,9 @@
self.backwards_compat = backwards_compat # note __setattr__
+ self._urlunparse = urlparse.urlunparse
+ self._urlparse = urlparse.urlparse
+
def __getattr__(self, name):
if name == "backwards_compat":
return self._backwards_compat
@@ -2680,6 +2826,8 @@
else:
control = klass(type, name, a, index)
control.add_to_form(self)
+ control._urlparse = self._urlparse
+ control._urlunparse = self._urlunparse
def fixup(self):
"""Normalise form after all controls have been added.
@@ -3057,7 +3205,8 @@
is_listcontrol, nr)
def _find_control(self, name, type, kind, id, label, predicate, nr):
- if (name is not None) and not isstringlike(name):
+ if ((name is not None) and (name is not Missing) and
+ not isstringlike(name)):
raise TypeError("control name must be string-like")
if (type is not None) and not isstringlike(type):
raise TypeError("control type must be string-like")
@@ -3079,7 +3228,8 @@
nr = 0
for control in self.controls:
- if name is not None and name != control.name:
+ if ((name is not None and name != control.name) and
+ (name is not Missing or control.name is not None)):
continue
if type is not None and type != control.type:
continue
@@ -3109,7 +3259,7 @@
return found
description = []
- if name is not None: description.append("name '%s'" % name)
+ if name is not None: description.append("name %s" % repr(name))
if type is not None: description.append("type '%s'" % type)
if kind is not None: description.append("kind '%s'" % kind)
if id is not None: description.append("id '%s'" % id)
@@ -3166,19 +3316,19 @@
"""Return a tuple (url, data, headers)."""
method = self.method.upper()
#scheme, netloc, path, parameters, query, frag = urlparse.urlparse(self.action)
- parts = urlparse.urlparse(self.action)
+ parts = self._urlparse(self.action)
rest, (query, frag) = parts[:-2], parts[-2:]
if method == "GET":
if self.enctype != "application/x-www-form-urlencoded":
raise ValueError(
"unknown GET form encoding type '%s'" % self.enctype)
- parts = rest + (urlencode(self._pairs()), "")
- uri = urlparse.urlunparse(parts)
+ parts = rest + (urlencode(self._pairs()), None)
+ uri = self._urlunparse(parts)
return uri, None, []
elif method == "POST":
- parts = rest + (query, "")
- uri = urlparse.urlunparse(parts)
+ parts = rest + (query, None)
+ uri = self._urlunparse(parts)
if self.enctype == "application/x-www-form-urlencoded":
return (uri, urlencode(self._pairs()),
[("Content-type", self.enctype)])
Modified: python-clientform/trunk/GeneralFAQ.html
===================================================================
--- python-clientform/trunk/GeneralFAQ.html 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/GeneralFAQ.html 2007-04-09 22:04:59 UTC (rev 771)
@@ -8,7 +8,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta name="author" content="John J. Lee <jjl at pobox.com>">
- <meta name="date" content="2006-01-05">
+ <meta name="date" content="2006-05-06">
<meta name="keywords" content="FAQ,cookie,HTTP,HTML,form,table,Python,web,client,client-side,testing,sniffer,https,script,embedded">
<title>Python web-client programming general FAQs</title>
<style type="text/css" media="screen">@import "../styles/style.css";</style>
@@ -26,10 +26,10 @@
<div id="Content">
<ul>
<li>Is there any example code?
- <p>There's (still!) a bit of a shortage of example code for ClientCookie
- and ClientForm &co., because the stuff I've written tends to either
- require access to restricted-access sites, or is proprietary code (and the
- same goes for other people's code).
+ <p>Look in the examples directory of <a href="../mechanize">mechanize</a>.
+ Note that the examples on the <a href="../ClientForm">ClientForm page</a>
+ are executable as-is. Contributions of example code would be very
+ welcome!
<li>HTTPS on Windows?
<p>Use this <a href="http://pypgsql.sourceforge.net/misc/python22-win32-ssl.zip">
_socket.pyd</a>, or use Python 2.3.
@@ -67,7 +67,7 @@
<code>CookieJar</code> instance, calling methods on
<code>HTMLForm</code>s, calling <code>urlopen</code>, etc.
- <li>Dump ClientCookie and ClientForm and automate a browser instead.
+ <li>Dump mechanize and ClientForm and automate a browser instead.
For example use MS Internet Explorer via its COM automation interfaces, using
the <a href="http://starship.python.net/crew/mhammond/">Python for
Windows extensions</a>, aka pywin32, aka win32all (eg.
@@ -127,7 +127,7 @@
<li>Will any of this code make its way into the Python standard library?
<p>The request / response processing extensions to <code>urllib2</code> from
- ClientCookie have been merged into <code>urllib2</code> for Python 2.4.
+ mechanize have been merged into <code>urllib2</code> for Python 2.4.
The cookie processing has been added, as module <code>cookielib</code>.
Eventually, I'll submit patches to get the http-equiv, refresh, and
robots.txt code in there too, and maybe <code>mechanize.UserAgent</code>
@@ -141,7 +141,7 @@
mailing list</a> rather than direct to me.
<p><a href="mailto:jjl at pobox.com">John J. Lee</a>,
-January 2006.
+May 2006.
</div> <!--id="Content"-->
@@ -152,11 +152,12 @@
<span class="thispage">General FAQs</span><br>
<br>
<a href="../mechanize/">mechanize</a><br>
-<a href="../pullparser/">pullparser</a><br>
+<a href="../mechanize/doc.html"><span class="subpage">mechanize docs</span></a><br>
+<a href="../ClientForm/">ClientForm</a><br>
+<br>
<a href="../ClientCookie/">ClientCookie</a><br>
<a href="../ClientCookie/doc.html"><span class="subpage">ClientCookie docs</span></a><br>
-<a href="../ClientForm/">ClientForm</a><br>
-<br>
+<a href="../pullparser/">pullparser</a><br>
<a href="../DOMForm/">DOMForm</a><br>
<a href="../python-spidermonkey/">python-spidermonkey</a><br>
<a href="../ClientTable/">ClientTable</a><br>
Modified: python-clientform/trunk/INSTALL.txt
===================================================================
--- python-clientform/trunk/INSTALL.txt 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/INSTALL.txt 2007-04-09 22:04:59 UTC (rev 771)
@@ -54,8 +54,8 @@
See the file COPYRIGHT.txt for copyright information.
This code in this package is free software; you can redistribute it
-and/or modify it under the terms of the BSD or ZPL licenses (see the
-file COPYING.txt).
+and/or modify it under the terms of the BSD or ZPL 2.1 licenses (see
+the file COPYING.txt).
John J. Lee <jjl at pobox.com>
March 2006
Modified: python-clientform/trunk/MANIFEST.in
===================================================================
--- python-clientform/trunk/MANIFEST.in 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/MANIFEST.in 2007-04-09 22:04:59 UTC (rev 771)
@@ -10,4 +10,3 @@
include *.py
recursive-include testdata *.html
recursive-include examples *.dat *.txt *.html *.cgi *.py
-recursive-include ez_setup *.py
Modified: python-clientform/trunk/PKG-INFO
===================================================================
--- python-clientform/trunk/PKG-INFO 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/PKG-INFO 2007-04-09 22:04:59 UTC (rev 771)
@@ -1,12 +1,12 @@
Metadata-Version: 1.0
Name: ClientForm
-Version: 0.2.2
+Version: 0.2.6
Summary: Client-side HTML form handling.
Home-page: http://wwwsearch.sourceforge.net/ClientForm/
Author: John J. Lee
Author-email: jjl at pobox.com
License: BSD
-Download-URL: http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0.2.2.tar.gz
+Download-URL: http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0.2.6.tar.gz
Description: ClientForm is a Python module for handling HTML forms on the client
side, useful for parsing HTML forms, filling them in and returning the
completed forms to the server. It developed from a port of Gisle Aas'
Modified: python-clientform/trunk/README.html
===================================================================
--- python-clientform/trunk/README.html 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/README.html 2007-04-09 22:04:59 UTC (rev 771)
@@ -2,18 +2,15 @@
"http://www.w3.org/TR/html4/strict.dtd">
<!--This file was generated by EmPy from README.html.in : do not edit-->
-
-
-
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta name="author" content="John J. Lee <jjl at pobox.com>">
- <meta name="date" content="2006-03-22">
+ <meta name="date" content="2006-10-25">
<meta name="keywords" content="form,HTML,Python,web,client,client-side">
<title>ClientForm</title>
<style type="text/css" media="screen">@import "../styles/style.css";</style>
- <base href="http://wwwsearch.sourceforge.net/ClientForm/">
+
</head>
<body>
@@ -267,9 +264,9 @@
<p>For full documentation, see the docstrings in ClientForm.py.
-<p><em><strong>Note: this page describes the 0.2 (development release)
-interface. See <a href="./src/README_0_1_18.html">here</a> for the stable
-0.1 interface.</strong> </em>
+<p><em><strong>Note: this page describes the 0.2 (stable release)
+interface. See <a href="./src/README-0_1_17.html">here</a> for the
+old 0.1 interface.</strong> </em>
<a name="parsers"></a>
@@ -338,7 +335,7 @@
deselected: AttributeError is raised in 0.2, whereas deselection was allowed in
0.1. The bug in 0.1 and in 0.2's backwards-compatibility mode will not be
fixed, to preserve compatibility and to encourage people to upgrade to the new
-0.2 <code>backwards_compat=True</code> behaviour. </ul>
+0.2 <code>backwards_compat=False</code> behaviour. </ul>
<a name="credits"></a>
<h2>Credits</h2>
@@ -369,8 +366,8 @@
<ul>
-<li><a href="./src/ClientForm-0.2.2.tar.gz">ClientForm-0.2.2.tar.gz</a>
-<li><a href="./src/ClientForm-0.2.2.zip">ClientForm-0.2.2.zip</a>
+<li><a href="./src/ClientForm-0.2.6.tar.gz">ClientForm-0.2.6.tar.gz</a>
+<li><a href="./src/ClientForm-0.2.6.zip">ClientForm-0.2.6.zip</a>
<li><a href="./src/ChangeLog.txt">Change Log</a> (included in distribution)
<li><a href="./src/">Older releases.</a>
</ul>
@@ -543,7 +540,7 @@
mailing list</a> rather than direct to me.
<p><a href="mailto:jjl at pobox.com">John J. Lee</a>,
-March 2006.
+October 2006.
</div>
@@ -554,11 +551,12 @@
<a href="../bits/GeneralFAQ.html">General FAQs</a><br>
<br>
<a href="../mechanize/">mechanize</a><br>
-<a href="../pullparser/">pullparser</a><br>
-<a href="../ClientCookie/">ClientCookie</a><br>
-<a href="../ClientCookie/doc.html"><span class="subpage">ClientCookie docs</span></a><br>
+<a href="../mechanize/doc.html"><span class="subpage">mechanize docs</span></a><br>
<span class="thispage">ClientForm</span><br>
<br>
+<a href="../ClientCookie/">ClientCookie</a><br>
+<a href="../ClientCookie/doc.html"><span class="subpage">ClientCookie docs</span></a><br>
+<a href="../pullparser/">pullparser</a><br>
<a href="../DOMForm/">DOMForm</a><br>
<a href="../python-spidermonkey/">python-spidermonkey</a><br>
<a href="../ClientTable/">ClientTable</a><br>
Modified: python-clientform/trunk/README.html.in
===================================================================
--- python-clientform/trunk/README.html.in 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/README.html.in 2007-04-09 22:04:59 UTC (rev 771)
@@ -3,10 +3,16 @@
@# This file is processed by EmPy
<!--This file was generated by EmPy from README.html.in : do not edit-->
@# http://wwwsearch.sf.net/bits/colorize.py
-@{from colorize import colorize}
-@{import time}
-@{import release}
-@{last_modified = release.svn_id_to_time("$Id: README.html.in 24825 2006-03-22 21:41:49Z jjlee $")}
+@{
+from colorize import colorize
+import time
+import release
+last_modified = release.svn_id_to_time("$Id: README.html.in 33738 2006-10-25 19:54:30Z jjlee $")
+try:
+ base
+except NameError:
+ base = False
+}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
@@ -15,7 +21,7 @@
<meta name="keywords" content="form,HTML,Python,web,client,client-side">
<title>ClientForm</title>
<style type="text/css" media="screen">@@import "../styles/style.css";</style>
- <base href="http://wwwsearch.sourceforge.net/ClientForm/">
+ @[if base]<base href="http://wwwsearch.sourceforge.net/ClientForm/">@[end if]
</head>
<body>
@@ -75,9 +81,9 @@
<p>For full documentation, see the docstrings in ClientForm.py.
-<p><em><strong>Note: this page describes the 0.2 (development release)
-interface. See <a href="./src/README_0_1_18.html">here</a> for the stable
-0.1 interface.</strong> </em>
+<p><em><strong>Note: this page describes the 0.2 (stable release)
+interface. See <a href="./src/README-0_1_17.html">here</a> for the
+old 0.1 interface.</strong> </em>
<a name="parsers"></a>
@@ -146,7 +152,7 @@
deselected: AttributeError is raised in 0.2, whereas deselection was allowed in
0.1. The bug in 0.1 and in 0.2's backwards-compatibility mode will not be
fixed, to preserve compatibility and to encourage people to upgrade to the new
-0.2 <code>backwards_compat=True</code> behaviour. </ul>
+0.2 <code>backwards_compat=False</code> behaviour. </ul>
<a name="credits"></a>
<h2>Credits</h2>
@@ -176,7 +182,7 @@
methods are still there, but some have been deprecated and a few added).
<ul>
-@{version = "0.2.2"}
+@{version = "0.2.6"}
<li><a href="./src/ClientForm-@(version).tar.gz">ClientForm-@(version).tar.gz</a>
<li><a href="./src/ClientForm-@(version).zip">ClientForm-@(version).zip</a>
<li><a href="./src/ChangeLog.txt">Change Log</a> (included in distribution)
Modified: python-clientform/trunk/README.txt
===================================================================
--- python-clientform/trunk/README.txt 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/README.txt 2007-04-09 22:04:59 UTC (rev 771)
@@ -1,5 +1,6 @@
- [1]SourceForge.net Logo
+ [1]SourceForge.net Logo
+
ClientForm
ClientForm is a Python module for handling HTML forms on the client
@@ -231,8 +232,8 @@
For full documentation, see the docstrings in ClientForm.py.
- Note: this page describes the 0.2 (development release) interface. See
- [4]here for the stable 0.1 interface.
+ Note: this page describes the 0.2 (stable release) interface. See
+ [4]here for the old 0.1 interface.
Parsers
@@ -289,7 +290,7 @@
whereas deselection was allowed in 0.1. The bug in 0.1 and in
0.2's backwards-compatibility mode will not be fixed, to preserve
compatibility and to encourage people to upgrade to the new 0.2
- backwards_compat=True behaviour.
+ backwards_compat=False behaviour.
Credits
@@ -312,8 +313,8 @@
0.2 includes better support for labels, and a simpler interface (all
the old methods are still there, but some have been deprecated and a
few added).
- * [10]ClientForm-0.2.2.tar.gz
- * [11]ClientForm-0.2.2.zip
+ * [10]ClientForm-0.2.6.tar.gz
+ * [11]ClientForm-0.2.6.zip
* [12]Change Log (included in distribution)
* [13]Older releases.
@@ -444,83 +445,85 @@
I prefer questions and comments to be sent to the [35]mailing list
rather than direct to me.
- [36]John J. Lee, March 2006.
+ [36]John J. Lee, October 2006.
[37]Home
[38]General FAQs
[39]mechanize
- [40]pullparser
+ [40]mechanize docs
+ ClientForm
[41]ClientCookie
[42]ClientCookie docs
- ClientForm
- [43]DOMForm
- [44]python-spidermonkey
- [45]ClientTable
- [46]1.5.2 urllib2.py
- [47]1.5.2 urllib.py
- [48]Other stuff
- [49]Example
- [50]Notes
- [51]Parsers
- [52]Compatibility
- [53]Credits
- [54]Download
- [55]FAQs
+ [43]pullparser
+ [44]DOMForm
+ [45]python-spidermonkey
+ [46]ClientTable
+ [47]1.5.2 urllib2.py
+ [48]1.5.2 urllib.py
+ [49]Other stuff
+ [50]Example
+ [51]Notes
+ [52]Parsers
+ [53]Compatibility
+ [54]Credits
+ [55]Download
+ [56]FAQs
References
1. http://sourceforge.net/
2. http://www.linpro.no/lwp/
3. http://pyunit.sourceforge.net/
- 4. http://wwwsearch.sourceforge.net/ClientForm/src/README_0_1_18.html
- 5. http://wwwsearch.sourceforge.net/ClientForm/#faq
+ 4. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/README-0_1_17.html
+ 5. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#faq
6. http://www.egenix.com/files/python/mxTidy.html
7. http://utidylib.berlios.de/
8. http://www.crummy.com/software/BeautifulSoup/
- 9. http://wwwsearch.sourceforge.net/ClientForm/#compat
- 10. http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0.2.2.tar.gz
- 11. http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0.2.2.zip
- 12. http://wwwsearch.sourceforge.net/ClientForm/src/ChangeLog.txt
- 13. http://wwwsearch.sourceforge.net/ClientForm/src/
- 14. http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0.1.17.tar.gz
- 15. http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0_1_17.zip
- 16. http://wwwsearch.sourceforge.net/ClientForm/src/ChangeLog.txt
- 17. http://wwwsearch.sourceforge.net/ClientForm/src/
- 18. http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0.0.16.tar.gz
- 19. http://wwwsearch.sourceforge.net/ClientForm/src/ClientForm-0_0_16.zip
- 20. http://wwwsearch.sourceforge.net/ClientForm/src/ChangeLog.txt
- 21. http://wwwsearch.sourceforge.net/ClientForm/src/
+ 9. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#compat
+ 10. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ClientForm-0.2.6.tar.gz
+ 11. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ClientForm-0.2.6.zip
+ 12. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ChangeLog.txt
+ 13. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/
+ 14. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ClientForm-0.1.17.tar.gz
+ 15. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ClientForm-0_1_17.zip
+ 16. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ChangeLog.txt
+ 17. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/
+ 18. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ClientForm-0.0.16.tar.gz
+ 19. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ClientForm-0_0_16.zip
+ 20. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/ChangeLog.txt
+ 21. file://localhost/home/lunar/debian/pkg-zope/python-clientform/src/
22. http://subversion.tigris.org/
23. http://codespeak.net/svn/wwwsearch/ClientForm/trunk#egg=ClientForm-dev
24. http://www.python.org/
25. http://www.opensource.org/licenses/bsd-license.php
26. http://www.zope.org/Resources/ZPL
- 27. http://wwwsearch.sourceforge.net/bits/GeneralFAQ.html
- 28. http://wwwsearch.sourceforge.net/ClientCookie/
- 29. http://wwwsearch.sourceforge.net/ClientCookie/doc.html#debugging
- 30. http://wwwsearch.sourceforge.net/bits/GeneralFAQ.html
+ 27. file://localhost/home/lunar/debian/pkg-zope/bits/GeneralFAQ.html
+ 28. file://localhost/home/lunar/debian/pkg-zope/ClientCookie/
+ 29. file://localhost/home/lunar/debian/pkg-zope/ClientCookie/doc.html#debugging
+ 30. file://localhost/home/lunar/debian/pkg-zope/bits/GeneralFAQ.html
31. http://www.w3.org/TR/html401/
32. http://www.ietf.org/rfc/rfc1866.txt
33. http://www.ietf.org/rfc/rfc1867.txt
34. http://www.ietf.org/rfc/rfc2616.txt
35. http://lists.sourceforge.net/lists/listinfo/wwwsearch-general
36. mailto:jjl at pobox.com
- 37. http://wwwsearch.sourceforge.net/
- 38. http://wwwsearch.sourceforge.net/bits/GeneralFAQ.html
- 39. http://wwwsearch.sourceforge.net/mechanize/
- 40. http://wwwsearch.sourceforge.net/pullparser/
- 41. http://wwwsearch.sourceforge.net/ClientCookie/
- 42. http://wwwsearch.sourceforge.net/ClientCookie/doc.html
- 43. http://wwwsearch.sourceforge.net/DOMForm/
- 44. http://wwwsearch.sourceforge.net/python-spidermonkey/
- 45. http://wwwsearch.sourceforge.net/ClientTable/
- 46. http://wwwsearch.sourceforge.net/bits/urllib2_152.py
- 47. http://wwwsearch.sourceforge.net/bits/urllib_152.py
- 48. http://wwwsearch.sourceforge.net/#other
- 49. http://wwwsearch.sourceforge.net/ClientForm/#example
- 50. http://wwwsearch.sourceforge.net/ClientForm/#notes
- 51. http://wwwsearch.sourceforge.net/ClientForm/#parsers
- 52. http://wwwsearch.sourceforge.net/ClientForm/#compat
- 53. http://wwwsearch.sourceforge.net/ClientForm/#credits
- 54. http://wwwsearch.sourceforge.net/ClientForm/#download
- 55. http://wwwsearch.sourceforge.net/ClientForm/#faq
+ 37. file://localhost/home/lunar/debian/pkg-zope
+ 38. file://localhost/home/lunar/debian/pkg-zope/bits/GeneralFAQ.html
+ 39. file://localhost/home/lunar/debian/pkg-zope/mechanize/
+ 40. file://localhost/home/lunar/debian/pkg-zope/mechanize/doc.html
+ 41. file://localhost/home/lunar/debian/pkg-zope/ClientCookie/
+ 42. file://localhost/home/lunar/debian/pkg-zope/ClientCookie/doc.html
+ 43. file://localhost/home/lunar/debian/pkg-zope/pullparser/
+ 44. file://localhost/home/lunar/debian/pkg-zope/DOMForm/
+ 45. file://localhost/home/lunar/debian/pkg-zope/python-spidermonkey/
+ 46. file://localhost/home/lunar/debian/pkg-zope/ClientTable/
+ 47. file://localhost/home/lunar/debian/pkg-zope/bits/urllib2_152.py
+ 48. file://localhost/home/lunar/debian/pkg-zope/bits/urllib_152.py
+ 49. file://localhost/home/lunar/debian/pkg-zope/#other
+ 50. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#example
+ 51. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#notes
+ 52. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#parsers
+ 53. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#compat
+ 54. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#credits
+ 55. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#download
+ 56. file://localhost/home/lunar/debian/pkg-zope/python-clientform/#faq
Modified: python-clientform/trunk/debian/changelog
===================================================================
--- python-clientform/trunk/debian/changelog 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/debian/changelog 2007-04-09 22:04:59 UTC (rev 771)
@@ -1,3 +1,12 @@
+python-clientform (0.2.6-1) unstable; urgency=low
+
+ * New upstream release. (Closes: #418460)
+ * Drop patch to ClientForm.py that has been integrated upstream.
+ * Re-generate README.txt with "lynx -dump" as upstream forgot to do it.
+ * Add myself as an Uploader.
+
+ -- Jérémy Bobbio <lunar at debian.org> Tue, 10 Apr 2007 00:04:05 +0200
+
python-clientform (0.2.2-3) unstable; urgency=low
* Back-port patch from Zope 3.3 release branch
Modified: python-clientform/trunk/debian/control
===================================================================
--- python-clientform/trunk/debian/control 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/debian/control 2007-04-09 22:04:59 UTC (rev 771)
@@ -2,7 +2,7 @@
Section: python
Priority: extra
Maintainer: Debian/Ubuntu Zope Team <pkg-zope-developers at lists.alioth.debian.org>
-Uploaders: Brian Sutherland <jinty at web.de>, Fabio Tranchitella <kobold at debian.org>
+Uploaders: Brian Sutherland <jinty at web.de>, Fabio Tranchitella <kobold at debian.org>, Jérémy Bobbio <lunar at debian.org>
Build-Depends-Indep: python (>= 2.3.5-7), python-all-dev, python-central (>= 0.5)
Build-Depends: debhelper (>= 5.0.37.2), python-setuptools (>= 0.6a9)
Standards-Version: 3.7.2
Copied: python-clientform/trunk/ez_setup.py (from rev 770, python-clientform/branches/upstream/current/ez_setup.py)
Copied: python-clientform/trunk/setup.cfg (from rev 770, python-clientform/branches/upstream/current/setup.cfg)
Modified: python-clientform/trunk/setup.py
===================================================================
--- python-clientform/trunk/setup.py 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/setup.py 2007-04-09 22:04:59 UTC (rev 771)
@@ -15,11 +15,11 @@
import re
#VERSION_MATCH = re.search(r'VERSION = "(.*)"', open("ClientForm.py").read())
#VERSION = VERSION_MATCH.group(1)
-VERSION = '0.2.2'
+VERSION = '0.2.6'
INSTALL_REQUIRES = []
NAME = "ClientForm"
PACKAGE = False
-LICENSE = "BSD"
+LICENSE = "BSD" # or ZPL 2.1
PLATFORMS = ["any"]
ZIP_SAFE = True
CLASSIFIERS = """\
Modified: python-clientform/trunk/test.py
===================================================================
--- python-clientform/trunk/test.py 2007-04-09 21:18:27 UTC (rev 770)
+++ python-clientform/trunk/test.py 2007-04-09 22:04:59 UTC (rev 771)
@@ -212,7 +212,33 @@
except AttributeError:
return req.headers.items()
+class MockResponse:
+ def __init__(self, f, url):
+ self._file = f
+ self._url = url
+ def geturl(self):
+ return self._url
+ def __getattr__(self, name):
+ return getattr(self._file, name)
+
class ParseTests(TestCase):
+
+ def test_failing_parse(self):
+ # XXX couldn't provoke an error from BeautifulSoup (!), so this has not
+ # been tested with RobustFormParser
+ import sgmllib
+ # Python 2.0 sgmllib raises RuntimeError rather than SGMLParseError,
+ # but seems never to even raise that except as an assertion, from
+ # reading the code...
+ if hasattr(sgmllib, "SGMLParseError"):
+ f = StringIO("<!!!!>")
+ base_uri = "http://localhost/"
+ self.assertRaises(
+ ClientForm.ParseError,
+ ClientForm.ParseFile, f, base_uri, backwards_compat=False,
+ )
+ self.assert_(issubclass(ClientForm.ParseError, sgmllib.SGMLParseError))
+
def test_unknown_control(self):
f = StringIO(
"""<form action="abc">
@@ -226,6 +252,84 @@
for ctl in form.controls:
self.assert_(isinstance(ctl, ClientForm.TextControl))
+ def test_ParseFileEx(self):
+ # empty "outer form" (where the "outer form" is the form consisting of
+ # all controls outside of any form)
+ f = StringIO(
+"""<form action="abc">
+<input type="text"></input>
+</form>
+""")
+ base_uri = "http://localhost/"
+ forms = ClientForm.ParseFileEx(f, base_uri)
+ outer = forms[0]
+ self.assertEqual(len(forms), 2)
+ self.assertEqual(outer.controls, [])
+ self.assertEqual(outer.name, None)
+ self.assertEqual(outer.action, base_uri)
+ self.assertEqual(outer.method, "GET")
+ self.assertEqual(outer.enctype, "application/x-www-form-urlencoded")
+ self.assertEqual(outer.attrs, {})
+
+ # non-empty outer form
+ f = StringIO(
+"""
+<input type="text" name="a"></input>
+<form action="abc">
+ <input type="text" name="b"></input>
+</form>
+<input type="text" name="c"></input>
+<form action="abc">
+ <input type="text" name="d"></input>
+</form>
+<input type="text" name="e"></input>
+""")
+ base_uri = "http://localhost/"
+ forms = ClientForm.ParseFileEx(f, base_uri)
+ outer = forms[0]
+ self.assertEqual(len(forms), 3)
+ self.assertEqual([c.name for c in outer.controls], ["a", "c", "e"])
+ self.assertEqual(outer.name, None)
+ self.assertEqual(outer.action, base_uri)
+ self.assertEqual(outer.method, "GET")
+ self.assertEqual(outer.enctype, "application/x-www-form-urlencoded")
+ self.assertEqual(outer.attrs, {})
+
+ def test_ParseResponse(self):
+ url = "http://example.com/"
+ r = MockResponse(
+ StringIO("""\
+<input type="text" name="outer"></input>
+<form action="abc"><input type="text" name="inner"></input></form>
+"""),
+ url,
+ )
+
+ forms = ClientForm.ParseResponse(r)
+ self.assertEqual(len(forms), 1)
+ form = forms[0]
+ self.assertEqual(form.action, url+"abc")
+ self.assertEqual(form.controls[0].name, "inner")
+
+ def test_ParseResponseEx(self):
+ url = "http://example.com/"
+ r = MockResponse(
+ StringIO("""\
+<input type="text" name="outer"></input>
+<form action="abc"><input type="text" name="inner"></input></form>
+"""),
+ url,
+ )
+
+ forms = ClientForm.ParseResponseEx(r)
+ self.assertEqual(len(forms), 2)
+ outer = forms[0]
+ inner = forms[1]
+ self.assertEqual(inner.action, url+"abc")
+ self.assertEqual(outer.action, url)
+ self.assertEqual(outer.controls[0].name, "outer")
+ self.assertEqual(inner.controls[0].name, "inner")
+
def test_parse_error(self):
f = StringIO(
"""<form action="abc">
@@ -285,10 +389,12 @@
self.assert_(len(forms) == 1)
form = forms[0]
self.assert_(form.name is None)
- self.assertEqual(form.action, "http://localhost/abc&"+u"\u2014".encode('utf8')+"d")
+ self.assertEqual(
+ form.action,
+ "http://localhost/abc&"+u"\u2014".encode('utf8')+"d")
control = form.find_control(type="textarea", nr=0)
self.assert_(control.name is None)
- self.assert_(control.value == "blah, blah,\nRhubarb.\n\n")
+ self.assert_(control.value == "blah, blah,\r\nRhubarb.\r\n\r\n")
empty_control = form.find_control(type="textarea", nr=1)
self.assert_(str(empty_control) == "<TextareaControl(<None>=)>")
@@ -499,7 +605,7 @@
form = forms[0]
self.assert_(form.controls[0].name is None)
- def testNamelessListControls(self):
+ def testNamelessListItems(self):
# XXX SELECT
# these controls have no item names
file = StringIO("""<form action="./weird.html">
@@ -621,7 +727,18 @@
single_control = form.find_control(type="select", nr=1)
self.assert_(single_control.value == ["1"])
+ def test_close_base_tag(self):
+ # Benji York: a single newline immediately after a start tag is
+ # stripped by browsers, but not one immediately before an end tag.
+ # TEXTAREA content is converted to the DOS newline convention.
+ forms = ClientForm.ParseFile(
+ StringIO("<form><textarea>\n\nblah\n</textarea></form>"),
+ "http://example.com/",
+ )
+ ctl = forms[0].find_control(type="textarea")
+ self.assertEqual(ctl.value, "\r\nblah\r\n")
+
class DisabledTests(TestCase):
def testOptgroup(self):
for compat in [False, True]:
@@ -2012,6 +2129,22 @@
else:
self.assertRaises(AmbiguityError, fc, label="Book")
+ def test_find_nameless_control(self):
+ data = """\
+<form>
+ <input type="checkbox"/>
+ <input type="checkbox" id="a" onclick="blah()"/>
+</form>
+"""
+ f = StringIO(data)
+ form = ClientForm.ParseFile(f, "http://example.com/",
+ backwards_compat=False)[0]
+ self.assertRaises(
+ AmbiguityError,
+ form.find_control, type="checkbox", name=ClientForm.Missing)
+ ctl = form.find_control(type="checkbox", name=ClientForm.Missing, nr=1)
+ self.assertEqual(ctl.id, "a")
+
def test_deselect_disabled(self):
def get_new_form(f, compat):
f.seek(0)
@@ -2974,7 +3107,62 @@
if compat:
reset_deprecations()
+ def test_nameless_list_control(self):
+ # ListControls are built up from elements that match by name and type
+ # attributes. Nameless controls cause some tricky cases. We should
+ # get a new control for nameless controls.
+ for data in [
+ """\
+<form>
+ <input type="checkbox" name="foo"/>
+ <input type="checkbox" name="bar"/>
+ <input type="checkbox" id="a" onclick="bar()" checked />
+</form>
+""",
+"""\
+<form>
+ <input type="checkbox" name="foo"/>
+ <input type="checkbox" id="a" onclick="bar()" checked />
+</form>
+""",
+"""\
+<form>
+ <input type="checkbox"/>
+ <input type="checkbox"/>
+ <input type="checkbox" id="a" onclick="bar()" checked />
+</form>
+""",
+ ]:
+ f = StringIO(data)
+ form = ClientForm.ParseFile(f, "http://example.com/",
+ backwards_compat=False)[0]
+ bar = form.find_control(type="checkbox", id="a")
+ # should have value "on", but not be successful
+ self.assertEqual([item.name for item in bar.items], ["on"])
+ self.assertEqual(bar.value, [])
+ self.assertEqual(form.click_pairs(), [])
+ def test_action_with_fragment(self):
+ for method in ["GET", "POST"]:
+ data = ('<form action="" method="%s">'
+ '<input type="submit" name="s"/></form>' % method
+ )
+ f = StringIO(data)
+ form = ClientForm.ParseFile(f, "http://example.com/",
+ backwards_compat=False)[0]
+ self.assertEqual(
+ form.click().get_full_url(),
+ "http://example.com/"+(method=="GET" and "?s=" or ""),
+ )
+ data = '<form action=""><isindex /></form>'
+ f = StringIO(data)
+ form = ClientForm.ParseFile(f, "http://example.com/",
+ backwards_compat=False)[0]
+ form.find_control(type="isindex").value = "blah"
+ self.assertEqual(form.click(type="isindex").get_full_url(),
+ "http://example.com/?blah")
+
+
class ContentTypeTests(TestCase):
def test_content_type(self):
import ClientForm
@@ -3003,6 +3191,32 @@
self.assertEqual(req.ah, not auh)
+class FunctionTests(TestCase):
+
+ def test_normalize_line_endings(self):
+ def check(text, expected, self=self):
+ got = ClientForm.normalize_line_endings(text)
+ self.assertEqual(got, expected)
+
+ # unix
+ check("foo\nbar", "foo\r\nbar")
+ check("foo\nbar\n", "foo\r\nbar\r\n")
+ # mac
+ check("foo\rbar", "foo\r\nbar")
+ check("foo\rbar\r", "foo\r\nbar\r\n")
+ # dos
+ check("foo\r\nbar", "foo\r\nbar")
+ check("foo\r\nbar\r\n", "foo\r\nbar\r\n")
+
+ # inconsistent -- we just blithely convert anything that looks like a
+ # line ending to the DOS convention, following Firefox's behaviour when
+ # normalizing textarea content
+ check("foo\r\nbar\nbaz\rblah\r\n", "foo\r\nbar\r\nbaz\r\nblah\r\n")
+
+ # pathological ;-O
+ check("\r\n\n\r\r\r\n", "\r\n"*5)
+
+
def startswith(string, initial):
if len(initial) > len(string): return False
return string[:len(initial)] == initial
More information about the pkg-zope-commits
mailing list