f = open(filename, 'rU')
, and have ALL newlines in the file be the single, normal, '\n'
character. Of interest is the new file object attribute, newlines:A file object that has been opened in universal newline mode gets a new attribute "newlines" which reflects the newline convention used in the file. The value for this attribute is one of None (no newline read yet), "\r", "\n", "\r\n" or a tuple containing all the newline types seen.This is especially welcome on "Mac OS X", as noted in the PEP, due to OS X's double standards - Classic and Carbon apps typically use the CR symbol to end a line, while Cocoa and Unix apps typically use LF.
tal:replace
on individual elements directly. Now, I still have my ability to mock up in "GoLive", combined with the ability to use Formulator's validation services.A quick example:
<div class="warning" tal:condition="options/errors/registration|nothing"> ... loop through validation errors here... </div> <form action="register.py" method="post" tal:define="form here/form_Register"> Full Name: <input type="text" name="fullname" size="29" tal:replace="structure python:form.fullname.render(REQUEST=request)">Using this technique, I was actually able to use two Formulator Form objects within a single HTML form - one handling registration details, one handling address details (which is expected to be used quite a bit in the site). The target Python script looks something like this:
etc... </form>
request = container.REQUEST errors = [] try: context.form_Register.validate_all_to_request(request) except FormValidationError, e: ## 'e' is an exception instance with a sequence of ## validation errors errors.extend(e.errors) try: context.form_Address.validate_all_to_request(request) except FormValidationError, e: ## Now extend the list of errors with Address validation errors errors.extend(e.errors) if errors: ## put the errors list in a dictionary in to distinguish which ## form the errors may have came from. return context['register.html'](request, errors={'registration':errors})There's still one area where I have problems with Formulator, and that's in
<select> .. <option>
widget generation. I seem to use different option values and contents (<option value="VA">Virginia</option>
) quite a bit in my sites, especially since Page Templates have made generating these even easier than in DTML. But I've had a hard time figuring out (a) how to even generate these types of option tags in Formulator (usually based off of the result of some script/method), and (b) how to do the equality "selected" testing when using a form on an existing object with a set value. It may be possible with stock Formulator, but it hasn't been obvious.On the public side of this site, Form Validation is going to be critical. It's nice not to have to roll-my-own solution yet again.
SELECT * FROM bands WHERE id NOT IN ( SELECT band_id FROM band_show_relationship WHERE show_id = :show_id )So, not having the ability to do sub-selects at this time, I tried doing all sorts of LEFT, RIGHT, LEFT OUTER, RIGHT OUTER variations, and failed. The main reason being that a band that's not on the playbill for a show yet won't be in the band_show_relationship table. So, the data set needs to include all bands that don't have any shows assigned, as well as ones that do but are NOT assigned to this show. I seriously thought an outer join might work, but every permutation either yielded too many results (the set of data I was trying to exclude was included) or none at all.So, after exhausting that route on my own, I went after the idea of collecting band id's for a particular show and then passing them into the SQL Method the page for assigning/unassigning bands was collecting that information anyways. And I was hoping the great sqltest DTML tag would help me here. Nope! I found a little buglet [Collector Issue 437].'sqltest' has a cool way of rendering "multiples". When used, the tag renders out
a = b
if only one value was passed in, and a in (b,c,d)
if a non-string sequence is passed in. You can also specify SQL operators to use via the op attribute of the tag, so that <dtml-sqltest band_id column="id" type=nb multiple op=ne>
will render a <> b
if a single value is passed in. However, the 'ne' operator doesn't pass through to the list. If a sequence is passed in, it still renders a in (b,c,d)
instead of a NOT in (b,c,d)
. Obviously, this can yield very incorrect results as passing in a single value, 'b', will exclude entries with 'b' from the result set; yet passing in a sequence of values, '(b,c,d)', will include 'b' (as well as 'c' and 'd') in the results.Crappy. So, I got to take a trip in my time machine and go back to the earlier Principia/Aqueduct days before the specialized SQL Methods tags and write my own list generator using dtml-in
, dtml-if sequence-start
and dtml-if sequence-end
to get the SQL that I wanted. And basically, I am now doing a sub-select because in order to get the list to place in the "not in show" method, I run my "bands in show" SQL Method and iterate over the band id's returned.Later, a coworker who's been using MySQL for far longer than I have came up to try to help me with the do it all in a normal query approach. Even between the two of us, we couldn't get it to work. I'm starting to think that the indexes might be to blame, or my logic is just plain wrong. But, we do have a solution in place.And it works. Elegant? no. Efficient? probably not. But, there's a big deadline and ultimately this is on a page that's not going to be used by the public-at-large, so we'll let it lie and wait for MySQL to support sub-selects. (Or I'll just sit and wish I had voted for PostgreSQL for this project when I had the chance).
Experiment: AppleScript Studio, Zope, XML-RPC. I want to try something. I think I can figure out a way to use AppleScript Studio to write an app to use XML-RPC calls to Zope to display Zope's object tree in an NSOutlineView. It initially seems like it will be pretty trivial, but I have some reading to do. Updates forthcoming... [via hoarfrost: zope, etc.]Nice. This is something I've meant to do, but never got all that far into AppleScripting the NSOutlineView. I did get this done, which I was pretty impressed with for my first time doing that much AppleScript - I came up with a good looking (and completely frivolous) application that worked within an incredibly short timespan.
<th align="left">
is super-cool. Then, it's on to dragging and dropping and - most importantly - sizing form elements. And then, a switch over to source mode (or Quick Tag Editing. Or even Outline Mode) to add in some TAL attributes, and it's done.
A beautiful satellite photo of nightfall over Europe...
Looks almost too good to not have been seriously processed, but is an awesome bit of imagery no matter what was done to it. [via bbum's rants, code & references]
parts.index(part_id)
because of the complex data structure of the list - although, if we had the object in question, we could try parts.index({'id': obj.getId(), 'meta_type': obj.meta_type})
. But the following works, and could be applied to any ObjectManager based class. Note - there are already Products available to bring order to Folders in Zope, such as Ordered Folder. It's a feature that was Proposed for Zope 2.6, but was deferred..class PartContainer(ObjectManager): def _findPartIndex(self, part_id, objectList=[]): """ Returns the index of a part in the object list """ idx = 0 for obj in objectList: if obj['id'] == part_id: break idx += 1 else: ## part not found raise IndexError(part_id) return idx security.declareProtected(change_scs_documents, 'movePartUp') def movePartUp(self, part_id): """ Move a part up. Raises IndexError if part is not found """ ## make a copy of our _objects list, which is a part of ObjectManager. ## _objects is a tuple of dictionaries with keys 'meta_type' and 'id'. parts = list(self._objects) idx = self._findPartIndex(part_id, parts) if idx == 0: ## Can't move past top, just exit return 0 ## swap fields, moving idx up parts[idx], parts[idx-1] = parts[idx-1], parts[idx] self._objects = tuple(parts) return 1 security.declareProtected(change_scs_documents, 'movePartDown') def movePartDown(self, part_id): """ Move a part down. Raises IndexError if part is not found """ ## make a copy of our _objects list, which is a part of ObjectManager. ## _objects is a tuple of dictionaries with keys 'meta_type' and 'id'. parts = list(self._objects) idx = self._findPartIndex(part_id, parts) if idx == len(parts)-1: ## Can't move past bottom, so just exit return 0 ## swap fields, moving idx up parts[idx], parts[idx+1] = parts[idx+1], parts[idx] self._objects = tuple(parts) return 1