ChangeLog¶
3.4.0 (released 2026-11-02)¶
The supported Python versions are now 3.10 to 3.15.
The development dependencies are now defined as dependency groups instead of the optional dependencies ‘tests’ and ‘docs’.
Setting select fields with ‘formvalue’ has been improved: Options inside optgroups are now found correctly (previously option texts and values could be mismatched), values with whitespace work, exact value matches take precedence, values with a leading ‘+’ or ‘-’ (such as ‘-1’) are first tried as they are, options can be chosen by their label or visible text even if it contains markup, disabled options are ignored like in a browser, and options with duplicate values are handled properly. Note that trying to select a disabled option now raises an error, while previously such an option was silently selected.
Deselecting an option of a single select field with ‘formvalue’ now clears the selection if this option was selected, so that the first option is used like in a browser. Previously this always tried to set an empty value and failed if there was no such option.
Checked checkboxes and radio buttons with an empty ‘value’ attribute are now submitted with an empty string like in a browser; ‘on’ is only sent when the ‘value’ attribute is missing. Previously, ‘on’ was also sent for empty values, due to an lxml bug. The same fix applies to the values shown with ‘showforms’. Twill now uses its own HTML parser that creates input elements with the fixed behavior. Checkboxes and radio buttons without a ‘value’ attribute can now also be selected with ‘fv’ using the default value ‘on’ when they are part of a group. As with select fields, checkbox values with a leading ‘+’ or ‘-’ are now first tried as they are, and checkboxes with duplicate values are handled properly.
The new command-line option ‘-s NAME=VALUE’ or ‘–set NAME=VALUE’ sets a global variable before the scripts are run, like the ‘setglobal’ command. This makes it easy to pass values such as an output directory to twill scripts. The command-line options are now also documented.
The new command ‘save_content’ saves the binary content of the current page, so that downloads such as PDF files can be stored unaltered, which was not possible with ‘save_html’. If no filename is given, it is taken from the ‘Content-Disposition’ header (including RFC 5987 encoded names) or from the URL. Filenames suggested by the server are reduced to their final path component, so that they can never be written outside the current directory, hidden names are ignored, reserved device names on Windows are prefixed with an underscore, and overlong names are truncated. ‘save_html’ now also respects the ‘Content-Disposition’ header, and percent-encoded characters in the URL are decoded when constructing a filename.
The new command ‘header’ asserts that the current page has been sent with a response header whose value matches a regular expression, e.g. ‘header content-type ^application/pdf’. The name of the header is case-insensitive, and like with ‘url’ and ‘title’, the matching part is stored in the variable ‘__match__’. The new command ‘show_headers’ shows all response headers of the current page.
The ‘info’ command does not fail any more when the current page has been sent without a ‘Content-Type’ header.
If the first group of a regular expression did not participate in the match, the commands ‘find’, ‘url’, ‘title’ and ‘header’ now set the variable ‘__match__’ to an empty string instead of None.
The command ‘find’ with the flag ‘x’ now also works with XPath expressions that return strings, numbers or booleans instead of elements.
The ‘Accept’ header sent by default was malformed (‘text/html; /’ instead of ‘text/html, /’); this has been fixed.
The command ‘extend_with’ now warns when an extension command replaces an existing variable.
The documentation of ‘follow’ now explains how the regular expression is matched against the link text and URL, and the documentation of ‘tidy_ok’ shows how to allow empty elements such as icons.
The documentation and the help text of ‘add_extra_header’ now use the correct name of the command (previously given as ‘add_extra_headers’ or ‘add_header’), the documentation of ‘form_clear’ now shows that it requires the name or number of the form, and the commands ‘redirect_error’ and ‘reset_error’ are now documented.
Support for AI coding agents has been added: The documentation now also provides the files ‘llms.txt’ and ‘llms-full.txt’, and the repository contains an agent skill for writing and running twill scripts that can be installed as a Claude Code plugin or used with other coding agents.
3.3.1 (released 2025-09-07)¶
The supported Python versions are now 3.8 to 3.14.
3.3 (released 2024-10-13)¶
The supported Python versions are now 3.8 to 3.13.
Saving and loading of cookies has been made more robust, and it now also incorporates the domains and paths of the cookies.
Twill now uses Flask instead of Quixote as test server for running its own test suite.
Twill now uses ‘argparse’ instead of the deprecated ‘optparse’ to parse options and arguments passed on the command line.
3.2.5 (released 2024-06-28)¶
Uses lxml 5 instead of lxml 4.
3.2.4 (released 2024-04-27)¶
Support latest version of httpx.
3.2.3 (released 2024-03-05)¶
Adds ‘timeout’ to the list of exported commends (#22).
3.2.2 (released 2024-01-28)¶
Fixes the broken interactive shell.
Fixes ‘run_file’ when specifying files in a subdirectory without extension.
3.2.1 (released 2023-11-23)¶
Increased the default request timeout of the twill browser to 10 seconds (from 5 seconds in 3.2) and added a command to change the timeout (#18).
3.2 (released 2023-11-02)¶
The supported Python versions are now 3.8 to 3.12.
A new method ‘find_links’ was added to the twill browser (#17).
WSGI apps are now supported via httpx, wsgi_intercept is not needed anymore.
We now use ‘pyproject.toml’ instead of ‘setup.py’.
Type hints and code style have been improved and are checked with ruff.
Internal code was reformatted using ruff format (compatible with black).
3.1 (released 2022-10-30)¶
The submit command now takes an additional parameter to specify a form that can be used in rare cases when there are no form fields (#7).
Most commands do not return values any more, they are just commands. If you are using twill from Python, you should check browser properties like ‘forms’ or ‘url’ instead of using the return values of commands like ‘show_forms’ or ‘back’ (see #13, #14).
Two-word commands now consistently have underscores in their names, (e.g. ‘form_action’, ‘get_input’, ‘show_links’). However, for convenience and backward compatibility, you can still use the names without underscores (e.g. ‘formaction’, ‘getinput’, ‘showlinks’), and the old two-letter abbreviations (e.g. ‘fa’ for ‘form_action’) (#13, #14).
Instead of ‘showforms’ or ‘show_forms’ you can now also write ‘show forms’, and similarly for ‘cookies’, ‘links’, ‘history’ and ‘html’. The command ‘show html’ does the same as ‘show’ without any arguments.
Renamed shortcuts for user agent strings, and added some more existing ones.
Added type hints (#15).
Support Python 3.11.
Many minor fixes and improvements.
3.0.3 (released 2022-10-12)¶
Form numbers are now printed correctly with ‘showforms’ (#12).
3.0.2 (released 2022-04-10)¶
Save HTML file with browser encoding or as UTF-8 (#9).
Do not modify root logger any more (#10).
3.0.1 (released 2021-12-04)¶
This version now also supports Python 3.10.
The twill language now allows 8-bit letters to appear in strings unquoted.
3.0 (released 2021-02-25)¶
In this version we require Python 3.6 to 3.9. If you still need support for Python 2 or Python 3.5, then please use the latest version from the 2.x branch.
The code has been optimized for Python 3 now.
Some minor fixes.
2.0.3 (released 2021-02-25)¶
Backported the fixes in version 3.0.
2.0.2 (released 2021-02-13)¶
This version now also supports Python 3.9.
‘tidy_should_exist’ has been renamed ot ‘require_tidy’.
Support for setting options to be used with HTML Tidy.
Cleanup scripts are now also read as UTF-8 in Python 3.
2.0.1 (released 2020-07-12)¶
Fixes an issue with encoding declarations (#5).
2.0 (released 2020-04-04)¶
This version is based on twill 1.8, which was a refactoring of version 0.9 that used requests and lxml instead of mechanize, done by Ben Taylor in April 2014. It also integrates ideas and code from Flunc which was created by Luke Tucker and Robert Marianski in 2006-2007, and from ReTwill which was created in April 2012 as a fork from twill 0.9 by Adam Victor Brandizzi. The following improvements and changes were made in this version:
Larger refactoring, clean-up and modernization efforts to support Python 2.7, 3.5 and higher.
The console script has been renamed from ‘twill-sh’ to just ‘twill’.
We assume the default file extension ‘.twill’ for twill scripts now.
Uses lxml and requests instead of mechanize (like in version 1.8), but doesn’t need cssselect and Beautiful Soup any more (unlike 1.8).
Removed bundled packages which have become unnecessary (mechanize) or are available in newer versions on PyPI (pyparsing, wsgi_intercept) or in the standard library (subprocess).
Removed parsing options (use_tidy, use_BeautifulSoup, allow_parse_errors) which have become insignificant due to the use of lxml.html.
A tox configuration file for running tests with different Python versions has been added.
Optimized the order of the URLs that are tried out by the twill browser.
Added an option ‘-d’ to dump the last HTML to a file or standard output and an option ‘-w’ to show the HTML directly in the web browser (this feature was taken over from Flunc).
Added alias ‘rf’ for ‘runfiles’ and made runfiles run directories of scripts as well. This helps writing test suites for twill scripts.
Added command ‘add_cleanup’ to unconditionally run cleanup scripts after the current script finished. This allows resetting the state of the tested server, so that tests will always re-run on a clean state. Together with a small init.twill script, this creates a test fixture. (This idea was taken from Flunc, which supports cleanup scripts for test suites, although in a somewhat different way.)
Non string values are now accepted in variable substitution (this feature has been backported from ReTwill).
XPath expressions are now supported in find/notfind commands (this feature has been backported from ReTwill).
Made output better controllable by using log levels (this feature has been backported from ReTwill). See options ‘-l’ and ‘-o’.
Updated the map of predefined user agent strings.
Basic authentication with realm is now supported again (the ‘with_default_realm’ option, which was broken in version 1.8, has been switched off).
Server certificates are not verified by default any more, since they are usually not valid on test and staging servers.
Improved handling of meta refresh. Circular redirects are detected and ‘debug equiv-refresh’ is functional again. A limit for the refresh time interval can be set with the ‘equiv_refresh_interval’ option. By default this is set to 2, so refresh intervals of 2 or more seconds are ignored.
Moved the examples and additional stuff into an ‘extras’ directory.
The documentation in the ‘docs’ directory has been updated and is now created with Sphinx.
Made sure everything (except twill-forks) also works on Windows.
Fixed a lot of smaller and larger bugs and problems.