+The main purpose of this release is to synch with the
+DurusWorks release and catch up on many small changes.
+Remove the ability for the publisher's 'ensure_signed_in' to
+take keyword arguments. If a specific realm is needed, then
+the publisher's version of ensure_signed_in should be overridden
+to provide the realm in calls to ensure_signed_in_using_form,
+ensure_signed_in_using_basic, ensure_signed_in_using_digest or
+one of the concrete implentations of ensure_signed_in.
+Change dulcinea implementation of ensure_signed_in keyword 'msg'
+to 'title' to match other concrete implementations in qp.
+Add a 'sign_in_page' key to the Hit info if we need to have the user
+sign in. This allows the header and footer parts to be customized for
+Don't delete the part BTree in Partition.remove if the part becomes empty.
+Do not try to produce a thumbnail for Photoshop files. PIL can't do it.
+Expand the list of safe tags for format_text.
+Add a css "popup" class to lots of pages.
+When formatting a note. Call nlnl2brbr to convert any two newlines
+in a row to two br tags. This makes non-html note formatting look
+FileStream keyword arg 'size' -> 'length'
+Add a module level function "static" that returns a path based on the
+path of the passed in module object. (util.py)
+Provide length of archive file to FileStream constructor.
+This allows range requests to apply to archive files. (browse.py)
+Add a new mixin Surveyed to dulcinea.survey which contains a ref to
+Add a new UI component SurveyedSurveysAndQuestionsUI which is a
+SurveysAndQuestionsUI but also updates the reference on the passed
+in Surveyed if provided.
+Use standard mimetypes module pattern for customizing guess_type() for use
+script, split the HTML output into two separate script tags.
+Don't require stored files to have mimetype in the predefined list.
+Add support for browsing into apk and jar files.
+Make thumbnails work, even without PIL.
+Avoid repeated categories in category.py.
+Add a SingleSelectAndString composite widget... which is really just the
+two widgets put together. Nothing fancy.
+Add get_stat() and get_mtime() methods to stored_file.
+Refactor some of the Table methods.
+Add Pager, a subclass of Table, intended to display search results that
+Simplify the display of the TableSearchForm form.
+Refactor SearchForm and TableSearchForm to have a 'format_matches' method
+to match the existing 'format_no_matches'. Implement SearchForm.render
+and TableSearchForm.render in terms of format_matches.
+Use "durus_id" as the name of the Durus persistent identifier. The old
+Add a show_grants module level function to dulcinea.ui.permission which
+when there's a granter, renders a table showing users granted any
+permission by this granter. The rendering of the user also includes
+a link to "Edit Permissions" for that user.
+Make the edit permission_form a component that must be custom if you need
+special behavour for get_valid_permissions or for side effects to grant
+Add undo_percent_quoting function that locates % quoted bytes and
+substitutes with unquoted byte values. This is useful when trying
+to eliminated overquoting.
+Attempt to make the TarfileWrapper has_member() method work in a variety
+of python versions, where there seems to be some variation in the way
+directory names are located in the archive.
+Change the Attachment UI so that the filename is used is both the alt tag and
+Change the _q_lookup of DataUI to only browse if the filename is not an image
+and the component is "browse", otherwise return the formatted thumbnail.
+Separate show_name_size_type into show_name, and show_size_type in
+attachment ui. Include file name in the file link.
+Change the 'required' widget from CheckboxWidget to RadiobuttonsWidget.
+CheckboxWidget is not added to the fields of the request if the box is
+not checked. This made turning off the requiredness of a property broken.
+This is in property_widget.py.
+Remove assertion about values in BigMultipleSelectWidget.
+The behavior should be the same as for MultipleSelectWidget.
+Make the default be to allow uploading of all types of files.
+Remove default 100% width for pretty table css.
+Add a get_form_keywords_matches method to SearchForm that returns the form
+object, keywords entered and the matches found for the entered keywords.
+Split out the __init__ of SearchForm to call get_form_keywords_matches.
+Remove 'match_substrings' keyword from SearchForm and all calls to it.
+The behavior now is to not match substrings and rather match on whole
+Move format_interaction_summary from dulcinea.ui.inquiry to
+0.18: svn revision 31367
+Convert stored datetimes to all be tz-aware. Existing databases
+that use these classes must be converted to work with this revision.
+Convert to be compatible with py3k.
+Convert code to use the newer names and template syntax of the
+Update RSSTab and RSSFeed to display an item's pubDate attribute.
+Add __hash__() methods where necessary.
+In py3k, __eq__() kills any inherited __hash__().
+that are constructed with 'show_hour_min' is True.
+Make Dulcinea safe for installations without sancho.
+Add a simple script for checking the URLs associated with links.
+Add charset attribute to StoredFile.
+Add Propertied Mixin for objects with a PropertyList.
+Revise some PropertyList methods.
+Add a highlight_keywords function that wraps any words present in keywords
+arg in a span with a "match" class.
+Make sortable headings work for server-side sorting.
+Add ability to make some columns not-sortable.
+Add even and odd classes to rows.
+0.17: svn revision 29799
+Use metaclass-loaded base classes, Specified, and Mixin, to nail down
+slot names for all data classes. Note that Specified base classes
+should come before Mixin base classes in a class definition. If they
+don't, you'll see an error about the class you are loading already having
+a __slots__ value. Instances of classes that derive from Dulcinea data
+classes will not have __dict__ attributes.
+Add an example update_db.py script to the qp demo site (in dulcinea/site).
+If anyone has an existing Durus database for a Dulcinea application, you
+should look at this. It shows how you can update a database to repickle
+objects that refer to, for example, 'Events', that now use slots for attributes
+and do not define their own __setstate__ methods. Without an update like
+this, existing applications will have unpickling errors. If you need help
+with this, please post questions to the qp mailing list.
+Add search capability to wiki.
+Add an 'invertable' keyword argument to BigMultipleSelectWidget that
+defaults to False. When invertable is True an "invert" button is
+added to the widget that when pressed inverts the selected and
+Care must be taken when using invertable BigMultipleSelectWidgets in
+forms, since pressing invert will cause form.is_submitted() to return
+Let the Master Property widget have a None value. The default is very
+unlikely to be the one that is desired.
+Improve CSS for PhysicalValueWidget and ToleranceWidget particularly
+Use the agent class as a css class in the BODY element.
+Make Categorized new-style.
+Make DulcineaUser specified.
+Make StoredFile slotted.
+Add search capability to wiki.
+Make Partition Persistent.
+Make sure that Specified comes before Mixin in every base class sequence.
+Add __eq__ and __ne__ to DulcineaPersistent.
+Change PhysicalUnit __cmp__ to __eq__.
+Make Copyable new-style, and simplify it.
+Implement copy() and __copy__() directly on DulcineaPersistent,
+and make DulcineaPersistent be a PersistentObject.
+This should allow some classes that are subclasses of DulcineaPersistent
+to use slotted attributes.
+Enhance the search for inquiries to look at the contact for the inquiry.
+Add placeholder file so that demo site has a var directory.
+Drop support for quixote applications. Dulcinea is all-QP now.
+This eliminates lots of complexity and redundant code.
+Applications that need to keep using quixote should stick to
+previous versions of Dulcinea.
+All files that were ptl files are now qpy files.
+datetime.strftime() needs a real str.
+Make the widgets of a BigMultipleSelect float left.
+This seems to make the qp rendering look like the quixote one.
+Make PersonNameWidget look the same on qp as it does on quixote.
+The three subwidgets should float left.
+allow the socket for the urlopen in an RSSFeed to timeout quickly if
+Disable abort in the test environment, so that a test session does
+not get tossed before a test request can be processed.
+Make page loader qp friendly.
+Don't write entire response body on failure.
+Add a 'user' keyword argument to the constructor of PageLoader
+Make the signin_link float right.
+This fixes a display problem on IE.
+Use Site() to open database.
+redirect(get_base_path() + x) -> redirect(x)
+Redirects always prepend the script name to paths that start with '/'.
+Prepending it in cases like this will cause it to appear twice in the
+Remove get_base_path(). (We now have complete_path() instead.)
+Move special SITE handling into set_test_environment().
+Don't depend on SITE in scripts. It is just for tests.
+Add an optional site_name keyword to the PageTest and CommonTest
+Import get_publisher and get_connection from qp.
+Remove access_denied and invalid_query.
+Use PersistentObject as the base class of more persistent classes.
+Don't make show_sidebar' keyword argument to hierarchy_header required.
+In lookup_user if matching on an email address and there are multiple matches,
+return the match that contains the user_id similar to the email address
+0.16: svn revision 29023
+Use slots on some classes to save memory.
+Rename Parameter to Property.
+Make sure that the publisher's add_user function is called on registration.
+Convert dulcinea Item and ItemFolder to be based on Keyed and Keep.
+Make Dulcinea Applications use the same Sessions with QP or Quixote.
+Remove the persistent SessionManager.
+Add get_time_zone() to DulcineaPublisher.
+Add site_now() to common.
+Add an open_connection() in the QP branch.
+Use users BTree instead of UserDatabase.
+The Publisher is the authoritative source, through get_users(),
+Move get_matching_user to the module level.
+Move gen_users_granted() to the module level.
+Make list_users() a module level function.
+Put a create_user on the Quixote Dulcinea Publisher.
+Export full sized PNG version of images.
+The user for password change history is also the logged in user not the user
+whos password is being changed.
+Add features to the debug UI.
+Make DulcineaUser use the qp hash function when running under qp.
+Under qp, if the digest matches using the dulcinea hash function,
+use the qp hash function to set a new, qp-compliant hash value.
+The qp hash function is preferred because it allows for http
+Suppress errors when search is submitted.
+When there is exactly one match, go ahead and select it.
+Fix css font family typo.
+Add the From Field of an inquiry to the searchable fields.
+Add search capability to links.
+Make html2txt more resilient to UnicodeDecodeError.
+Use the latin1 charset for the password reset email.
+0.15: svn revision 28637
+Fix a chicken/egg error in the setup.py. It imports __version__
+from __init__.py, and __init__.py expected dulcinea to already be
+Cache date_pair form pages.
+Make user code more qp-compatible.
+Remove _q_index() from DynamicExportingDirectory.
+This would only be used in a case where we export ('', '_q_index', None, None)
+and don't provide any explicit '_q_index'. If there are index pages that
+don't load after this change, those directories should implement _q_index,
+perhaps by calling index_page() as was done here.
+Implement a quixote-compatible version of Directory and put it in common.
+Change all imports of DynamicExportingDirectory to import Directory from
+Put get_directory_tree() in common.
+Remove enabling_cookies template and calls.
+0.14: svn revision 28488
+Make Attachment Persistent. To convert our databases containing attachments
+to the new form, we ran this function in our update script.
+ def touch_attachables():
+ from dulcinea.attachable import Attachment, Attachable
+ Attachment.__init__ = lambda x: None
+ for attachable in gen_every_instance(get_connection(), Attachable):
+Fix a bug in the change user password form that was not properly
+removing the user's password.
+Simplify the logic for SearchSelectOneWidget.
+Update get_crumb_tree to use a get_crumb_tree_menu_items generator function
+and to return, in addition, a derived css_class.
+Remove module level get_exports function from dulcinea.ui.crumbs. Instead
+assume all directories have get_exports methods.
+Move dulcinea.ui.crumbs.get_crumb_tree to dulcinea.ui.directory so it
+can be more easily used by code not using qpy.
+Make a StaticDirectory in dulcinea.common for quixote derived from the
+quixote StaticDirectory that has a get_exports method.
+Change all imports of StaticDirectory and StaticFile to go through
+Add page_size selection to search form.
+When the permission form change a permission granted by a granter
+to a user, call the granter's update_permission_cache() method, if it
+exists. This allows granters to maintain sets of users derived
+Don't use tokens on the date_pair_form, since it is ordinarily used
+for forms that are really just queries.
+0.13: svn revision 27891
+This is a kind of transitional release as we are using qp more.
+Our existing dulcinea-based applications are still using quixote and ptl.
+Define dulcinea.common to provide commonly used functions, and, in particular,
+to provide the quixote version to quixote applications and the qp version to
+Remove the ObjectDatabase class. Just call get_connection() and you
+get a connection to the durus storage that is configured for the
+site (and the site is determined by the SITE environment variable).
+If you want a file storage connection instead, call
+open_connection('foo.durus'). When the Connection is made, so is
+a site-specific Publisher.
+Make DulcineaUser class inherit from qp's User class. Existing DulcineaUser
+instances must be converted because the password digests are stored differently.
+A revise_users() function is provided for this conversion.
+Also make DulcineaUserDatabase inherit from qp's UserDatabase.
+Remove use of local_ui and local in dulcinea, although dulcinea.local
+is still be defined when the site provides a local module.
+Use get_publisher().get_site_title() instead of local.SITE_NAME.
+Use dulcinea.common.CommonTest for unit tests involving a Connection.
+dulcinea.sendmail.sendmail() uses publisher.get_webmaster_address() instead
+Database root accessors are now defined on the site-specific publisher,
+and used through access functions. For example, get_news_db() is defined
+in news.py. It calls the method on the publisher, and the DulcineaPublisher
+provides a default implementation.
+Add a dulcinea.uiqp package that mirrors the dulcinea.ui package,
+except using the qpy compiler instead of the ptl compiler.
+Make stronger attribute specification on History class so that Event
+instances can be more easily verified.
+LinkTripleDatabase business code and UI was separated from the
+Use sorted() instead of function_sort().
+Remove the keyed, permission modules.
+Revise debug session browser.
+0.12: svn revision 27720
+Dulcinea now requires the qp and qpy packages.
+Some Persistent classes that were in Dulcinea are now being used
+from qp instead, and more will move in future releases of Dulcinea
+as Dulcinea evolves to adapt to qp.
+Keeping up with these changes will involve changing imports and
+writing database update scripts.
+The keyed module is gone: where it was used, we are now using qp.lib.keep.
+Upgrading a database with KeyedMap instances will require a conversion
+script that converts them to Persistent Keep instances.
+The spec module is now imported from qp.
+The typeutils module, deprecated in the last release, is now gone.
+The code_utils module, and the utilities that used it are all removed, since
+the same functionality is available from qpy's qpcheck.py script.
+The DulcineaBase class is now named "Copyable".
+The Publisher class can be named in the site_config file now.
+This prepares the way for site-specific Publisher classes.
+wrap_text() is now safer for non-ascii str instances.
+0.11: svn revision 27556
+Change the DulcineaPublisher to set quixote's default encoding to utf8.
+This means form values are unicode, not strs. That means that non-ascii
+str instances are hazardous, since they won't be automatically decoded
+when they are combined in some way with unicode instances. It also means
+that calls to str() are hazardous, since the argument may now be a
+unicode instance that can't be encoded as ascii. We tried to identify
+these hazards and change them into calls to stringify(). Note also that
+"%s" % x is hazardous if x is an object with a __str__ method that may
+return a unicode instance. Code like this should be changed to
+Add functions to dulcinea.util that we used to try to recover characters
+from str instances with unknown encodings. Purge the old replace_characters()
+function that made this task more difficult.
+Add a "string" spec that includes ascii-only str instances and all
+unicode instances. Change attribute specifications everywhere from
+This release includes a revision to the way permissions are stored.
+The permissions.py module is deprecated, but for now it includes
+a function that may be helpful in converting an existing database
+to the new model. In short, the new model stores permissions on
+the users instead of on the objects that "grant" the permissions.
+The new model also uses PermissionSet, a class that is new in
+Use require() instead of typecheck() everywhere. The typeutils.py module
+is still included, but deprecated.
+Alter Keyed class to keep a counter on a separate persistent instance.
+Add a "pattern" spec. Thanks to Mario Ruggier for the idea.
+0.10: svn revision 27465
+Use specified attributes more.
+Add add_getters(), add_setters(), and add_getters_and_setters() to
+the spec module. Use these to add trivial get_<name> and set_<name>
+methods as needed for classes with specified attributes.
+Add a PersistentSet implementation.
+Add an Outline implementation.
+Convert spec's 'any' to 'either' and 'all' to 'both'
+to avoid collision with new builtins 'any' and 'all' in python 2.5.
+Allow some attributes that were specified as 'str' to be 'basestring'.
+Expand Phone number fields in the registration form to 20 chars
+Use a factored out module level function from dulcinea.address
+to determine if a phone number is valid.
+Use default value in get_cache_size().
+Add utilities 'set_environment' and 'clear_environment' to help test ui code.
+ - set_environment sets up a Quixote publisher with a request
+ - script_name, path_info, and other variables may be passed in as keywords
+Remove special handling of TIDY_CHECK in site scripts.
+Replace ._p_changed = 1 with ._p_note_change() in lots of places.
+it is actually required to get the right behavior.
+Change check_durus.py so that it no longer depends on grouch.
+It now expects all attributes to be specified using the spec pattern.
+Make a new general-purpose composite-widget PairWidget.
+Make DatePairWidget subclass from PairWidget
+In the browse module, force the mime-type for Python source code files
+Enhance enabling_cookies template to *not* assume that the version
+returned from HTTPRequest.guess_browser_version is always a string
+with at least one character.
+Use SCGIMount in dulcinea site script for apache.
+Remove extent module. Durus (>2.0) has a gen_every_instance() function that
+Add life_cycle_util module.
+Add size statistics to the check_durus output.
+Remove code-coverage stuff from dulcinea that is duplicated in the sancho
+Use decorators in the category ui code.
+Change spec's match() function so that a tuple containing None or
+a numeric or string literal is treated as a disjunction.
+This makes (None, int) mean the same thing as any(None, int),
+and it has the advantage of not requiring an import from the spec
+Add render_csv() to Table.
+Add rss support for tabbed views.
+Make all calls to format_user go through local_ui.
+Show 5 most recent history when formatting a user's profile if the
+logged in user is admin.
+Show [browse] link for browsable attachments.
+Provide a default local and local_ui for tests.
+Add browse.ptl, with support for browsing down into stored files
+that are tar or zip archives.
+Add get_module_directory() to dulcinea.util.
+Move thumbnail-generation code from attachment.ptl to thumbnail.ptl.
+Allow zip files to be uploaded as stored files.
+Simplify decoration-related parameters of Interactable mixin class.
+Restore reset_password to the profile page.
+Remove references to SessionError.
+Put revised signin handling in dulcinea.ui.user.util.
+Stop dropping userid cookies.
+Stop supporting insecure_login.
+Add safe_respond() to use for error responses.
+Change finish_interrupted_request() to make sure that cookies, set by the
+session manager, make it into the response.
+Make 'profile' a top-level directory that leads to individual user profiles
+Add a page() utility in dulcinea.ui.util.
+Add HUB-based scgi restart to site command. This is fast, but it does
+Use a Dulcinea version of Quixote Directory class. Instead of using
+_q_exports, the new DynamicExportingDirectory classes implement a
+get_exports() method, which generates a sequence of
+(url_component, attribute_name, crumb, crumb_title) tuples
+for the exports. See dulcinea.ui.directory for the implementation.
+Implement RespondNow handling behavior for the Dulcinea Publisher
+and use it for redirects, not signed in, invalid query, and
+not found responses. This is now the only PublishError subclass
+provided in Dulcinea. The error-handling changes can be found in
+in dulcinea.ui.publisher and dulcinea.ui.errors.
+Add a new Table class for rendering data tables that sort by
+column. The Table class supports sorting on the client side or
+Make opendb functional when readline is not available.
+Use the word "category" everywhere we are talking about Category
+instances. Stop using "group" for this purpose.
+Use not_found(), invalid_query() and access_error() instead of raising
+Use ensure_signed_in instead of NotLoggedInError.
+Make is_running() more portable.
+Use format_date() and format_date_time() from local_ui.
+Change none_quote() to return '' if the value is false.
+Call str on the method name so that method_sort can be called from templates,
+where the method name will normally be an htmltext instance.
+Use new quixote html_url function to generate url's with querystrings.
+Add a general page_loader: see dulcinea.ui.page_loader.
+This allows for sancho-style unit tests for a site.
+Revise the crumb formatting to include drop-down crumb menus and
+a menu of exports from the current Directory.
+Expand output of start-apache.py to include the interfaces for each site.
+Add a Message-of-the-day capability to DulcineaUser and DulcineaUserUI.
+ * Use Timestamped mixin for Survey, Comment, and Item.
+ * 'get_url' -> 'get_local_url'
+ * Use Quixote 2. Make all Quixote namespaces Directory instances.
+ Use quixote.server.scgi_server module.
+ * Move most of the code from sitecheck.py into dulcinea.traversal.
+ Change the behavior so that it does not complain about missing
+ attributes when there is a _q_resolve present.
+ * Move utest.py to sancho.
+ Add convert.py script in sancho.
+ Add utest_* for each test_* in durus/test and dulcinea/lib/test
+ * Add a configurable 'base_path' that will be prepended to absolute
+ URLs. Use relative paths when possible.
+ * Make stored_file more portable and improve attachment mime type handling.
+ * Make DateTimeSelectWidget more resilient to unusual dates.
+ datetime.strftime only works for year >= 1900
+ * Add a browse page that lists all urls reachable without _q_lookup, and
+ makes a little form for each significant _q_lookup that it finds.
+ * Make QuestionDatabase persistent.
+ * For consistency, change get_*_database() to get_*_db().
+ * In site_util, add get_docroot() and change _import_class() to import_class().
+ * Remove comma_format and test. Add a test for csv().
+ * Improve BigMultipleSelectWidget behavior.
+ * Remove immutable_list module and test. Use ImmutableSet instead.
+ * Add the ability to disable DulcineaUser.
+ * After a successful partial registration, redirect to the newly added
+ user's profile, not the login page.
+ * Get format_user from local_ui.
+ Add experimental DurusDirectory for browsing the durus database.
+ The browsing is disabled when is_live() is true.
+ * Allow users to sign in using either there user id or email address.
+ Add capability to disable login by email address
+ * Rename LazyModule class as SiteModule.
+ Protect import of site_config so that it is possible to import from
+ dulcinea without any installed site_config (as long as SITE is not set).
+ * Ensure absorbed objects get repicked since we bypass the persistence hook
+ * Fix sorting on ItemFolder.get_recent_items
+ * Create an html2txt() to util module
+ * Add interaction logging support.
+0.4: svn revision >25025
+ * Revise site_utils to get site configuration information from
+ a "site_config.py" module, expected on the normal python path,
+ instead of from the site.conf file. If you are using the site-related
+ code, you must write a site_config.py file for your site(s).
+ See site_util.get_config_value.__doc__ for a description of what
+ must be in your site_config.py file. Notably, the site configuration
+ variable names that included '-' are all converted to use '_' instead.
+ * Added pages for viewing publihser and site config values to the
+ * Allow address widget and contact address widget to work with a None value.
+ * Add site support for specifying the ability to do anonymous registration
+ * Cleanup URL space for attachment DataUI and allow multiple files
+ to be copied to the clipboard.
+ * Treat Address and ContactAddress as immutable.
+ * Remove FileDatabase class because our external files are always
+ accessed through attachments. Refactor code in the stored_file
+ module, making new_file() and guess_mime_type() functions instead
+ * Rewrite get_url() function. Behavior is now slightly different
+ but clearer and probably better. If 'secure' is false then don't
+ bother monkeying with the port, just return a full URL. If
+ 'secure' is true then attempt to use SSL. Note that if you want
+ SSL then site_config.config must provide a value for 'https_address'.
+ * Start Apache if 'httpd' is defined as a site_config value..
+ * Remove local.SUPPRESS_EMAIL flag and replace it by
+ site_util.is_email_enabled(). If email is not not enabled then
+ the dulcinea.sendmail module never sends mail. This is less
+ confusing than the SUPPRESS_EMAIL flag.
+ * Add Attachable.is_image() . Don't provide thumbnails for
+ * Use optional 'apache_version' directive so that start-apache.py
+ generates a config that can work with apache2, and the apache2
+0.3: svn revision >24702
+ * More use of Form2 forms.
+ * Replaced all use of mx.DateTime with the standard datetime.
+0.2.1: svn revision >23475
+ * Since 0.2, there are some classes to support a survey capability,
+ and improved unit test coverage.
+0.2: svn revision ~23344
+ * Second release. Many changes since 0.1.
+0.1: svn revision ~21750