The week in qooxdoo (2009-07-03)

Here's another weekly report, which collects input from the various core developers (thanks, guys!) and tries to massage it into a (mostly) coherent and appealing blog post ...

Form API

We introduced a new property on some form widgets called placeholder. Perhaps you already know what to do with it? If, for example, a TextField is empty, the placeholder will be displayed in a light grey font to give hints on what to enter. Five widgets did get this placeholder feature:

To see the placeholder feature in action, take a look at the form demo in the online demobrowser.

Another new feature in the input fields is the possibility to filter the input. The following code snippet shows how it could be used.

var textfield = new qx.ui.form.TextField();
textfield.setFilter(/[0-9]/);

This feature in the input fields allowed us to improve the spinner and the ColorSelector.

ComboBox

A ComboBox is like a TextField with a drop down of predefined values. A ComboBox is often used to improve usability. For instance, an app developer could add the least recently used (LRU) values to the drop down. This is quite convenient for the user when required to enter a value.

Of course, there are other use cases for the ComboBox. The main difference to the SelectBox is that the user can enter individual values or choose from the pre-defined ones. A question remains: should the ComboBox have a text value set initially?

This question can really only answer the app developer depending on his/her specific use case. At least the ComboBox shouldn't set any text value per default. But this was the behavior implemented so far, the ComboBox used the value of the first element of the drop down to initialize the text field. Also by looking at other toolkits and OS interfaces we decided to account for that common behavior: the ComboBox initializes with an empty value for the TextField (of course, if no value was set programmatically). That's the way it's implemented in the current SVN trunk. So you might consider adjusting your code when working with the trunk.

An XmlHttpRequest oddity

Two failing qx.io.remote unit tests exposed what looks like a bug in Safari 3 and Firefox 1.5: If a qooxdoo application has a qx.ui.embed.Iframe with another qooxdoo app running inside, some AJAX requests sent by the inner app using relative URI paths will lead to 404s: The XmlHttpRequest implementation in both browsers seems to treat URIs as if it was running in the topmost browser frame, so that, in a case like the qooxdoo Test Runner where the embedded application is located in a subdirectory of the outer application, that directory will be omitted from the GET requests sent to the server.

Granted, this use case is fairly specific and both browsers are obsolete, but we'd still like to hear from anyone out there who might have run into this issue before.

RPC Perl

Tobias Oetiker has put forth the first release 0.1 of the RpcPerl contribution, a server-side implementation of the qooxdoo RPC in Perl, making this the fourth contribution kit (i.e. archive) online at sourceforge.net. The new release is a brushed-up, but fully backwards compatible version of the so far unreleased software. Taking this opportunity, a new piece of documentation has been added that details the process of creating a SourceForge release from a contribution.

Online Demos

All demos at demo.qooxdoo.org are back to a standard-port, non-redirect implementation, so all issues with blocking firewalls and lost fragment identifiers should be gone :-) .

Bugfixes

For a complete list of bugs fixed during the last week, use this bugzilla query.

Community Award

As you should already know, qooxdoo has been chosen as a finalist in the annual SourceForge.net Community Choice Awards. It would really be great if you supported the project byvoting for qooxdoo in the category Best Visual Design. Thanks!

Have a nice weekend.

Ternary Operator

The conditional or ternary (because it involves three operands) operator is probably familiar to most programmers working with C-style programming languages. JavaScript adopts it right away:

  condExp ? thenExp : elseExp

All three operands are expressions, and the resulting expression means "If the condExp expression evaluates to true, return the value of the thenExp, otherwise that of the elseExp."

Until version 2.5 Python didn't have a ternary operator. When the operator was introduced it adopted a different approach to the syntax:

  thenExp if condExp else elseExp

but the semantics remain the same.

Prior to version 2.5 Python programmers would come up with all kinds of funny hacks to approximate this operator. Here are some of them:

  condExp and thenExp or elseExp           (1)

  (condExp and [thenExp] or [elseExp])[0]  (2)

  (thenExp, elseExp)[not condExp]          (3)

  (elseExp, thenExp)[bool(condExp)]        (4)

As you can see all cases involve logical operations, and some add sequence operations as well. You might want to ponder why this works and what the differences between the versions may be. For example, both (3) and (4) rely on the fact that not and bool turn True and False to 1 and 0 in list context, which is not entirely intuitive if you know that they are supposed to construct boolean values. (2) uses list construction ([...]) and deconstruction ([0]) to do basically the same as (1). The difference is rather subtle: In (1), if the condExp evaluates to true, the thenExp should be returned. But if the thenExp evaluates to false, the whole and expression evaluates to false too, and the elseExp is wrongly returned. (2) prevents this since a list containing only the False value is itself true.

Another general aspect of those approximations is that of evaluation of operands. In (1) and (2) the short-circuit evaluation of the logical operands assure that elseExp is never evaluated when condExp is true. In contrast, (3) and (4) evaluate both elements as part of the tuple construction before the accessor selects one of them. This may make a difference if they contain e.g. calls to function.

The week in qooxdoo (2009-06-26)

It's just the end of the week, not the end of the world, so here comes a freshly baked status report:

Yes we can

This is a call of duty to every reader of this post: qooxdoo has been chosen as a finalist in the annual SourceForge.net Community Choice Awards. During the first voting phase it became a nominee for Best Visual Design (sure, other categories might have worked out as well, but we go for Gold now in this one).

The final voting phase for the 2009 Awards has just begun, so please click on the badge and vote for qooxdoo. On the page that'll appear are a number of categories with 10 projects each. Feel free to vote for any other SF projects you like. If you don't care, just pick qooxdoo for Best Visual Design. Thanks for your support!

Flow Layout

This week the Flow layout manager has been re-added to qooxdoo. It hasn't been part of the framework since the 0.8 release.

Gallery widget implemented using a flow layout

Gallery widget implemented using a flow layout

A flow layout renders widgets just as a word processor renders text. Widgets are placed one after the other until there is no space left. If a widget doesn't fit into the remaining space of the current line, a new line is created and the widget is placed at the beginning of the new line. This layout manager can for instance be used to implement a gallery widget. The flow layout is based on the excellent community contribution by Chris Banford (Thanks!).

Memory leaks

We spent some time for checking for and fixing potential memory leaks in demo browser and framework core code. Just a reminder for anybody to check their applications for memory leaks, please have a look at the "Memory Management" article. This article describes how qooxdoo does a good job in assisting you to detect and fix memory leaks.

Core Fixes

We discovered three bugs right in the core system of qooxdoo this week. All of them were fixed immediately.

The first bug was in the check routine for interfaces. Remember that the property system auto-generates accessor and mutator methods for properties on demand. For Boolean properties two additional accessors, isPropertyName() and togglePropertyName() are created. But the interface check did not recognize these two methods so the check failed if you declared one of those methods in the interface.
The second bug was in the property system. A property with an init value returns on first access, right, the init value. Nevertheless, the corresponding change event contained null as old data value.Take a look at the following code showing the problem.

var m = new qx.ui.core.Widget();
m.getVisibility(); // returns the init value "visible"
 
m.addListener("changeVisibility", function(e) {
  e.getData(); // "hidden"
  e.getOldData(); // BUG: null and not the init value "visible"
});
m.setVisibility("hidden");

The third bug was in the destructor of qx.core.Object. If a property contains a reference type as value, these references weren't deleted during disposal, which could cause some memory problems. As already mentioned, all three bug were fixed during the week.

Form API

We fixed some minor details on the recently introduced form API. The new properties valid, invalidMessage and required do now fire events on every change. This has been missing in the former implementation.
Another change in the area of the form elements has been made in the abstract base class of all textfields. There has been a bug for deprecating the input event and introducing a property which changes the behavior of the changeValue event. The newly introduced property is called liveUpdate, whose default is false. So nothing should break, if you want to use the textfield like you used to. Switching the property to true causes the event to be fired on each key stroke instead of being fired when setting the final value.

Data Binding

We are interested in getting to know about all the issues you come across when using the data binding layer. We try to fix the incoming bugs as quickly as possible. So if you notice a weird behavior in the data binding (no matter how minor), please add a report to our bugtracking system.

Inline bug

A nasty bug in IE broke the layout for inline roots. A text-align style set to center on any surrounding element was sufficient to break the whole layout inside an inline root. Thanks to an excellent bug report from Jean-Noel Rivasseau, this bug could be fixed quickly.

IE8 debugging console

Since the 0.8.2 release qooxdoo supports the IE8 debugging console, but the legacy release 0.7.4 didn't. This missing feature was backported to the legacy branch in the SVN repository. A little note about the IE8 debugging console: the JavaScript object for calling the IE8 console method is only available after the "Developer Tools" were opened once. So don't worry if e.g. the logging window (qx 0.7.x) appears. Just open the "Developer Tools" and reload your application, which activates the console object and the log messages show up in the console.

Bugfixes

The usual can of worms has all the bugs that were fixed during the week.

qcl: PHP-based application framework

Christian Boulanger is currently upgrading the qcl project at qooxdoo-contrib. In his post to the mailing list had all the details about the project and a demo link. If you are also interested in the following features, please let him know:
"[...] basic building blocks for a fully featured web application:

  • server-side authentication and access control using users, roles,
    permissions
  • login and session management with fully transparent sessions
  • configuration values synchronized between server and client
  • GUI access control using permissions"

New real-life example

Andreas Fink let us all know about a cool qooxdoo app they're using. See the detailed description of their ReForm application and several screenshots of it (mmh, doesn't a qooxdoo 0.8.x application look great in the Modern theme?). Thanks Andreas for the info.

That's a perfect chance to remind everyone to add his/her application to the real-life examples as well. As with the latest addition, of course you don't have to supply online access to it if it's an enterprise and not a public internet solution. A short description and a nice screenshot is all it takes to inform the community and any (potentially new) users.

Whatever your plans for the weekend are, have fun. We certainly will, as we're about to head to the legendary, annual 1&1 summer fest. Partying with so many colleagues tonight will again be a blast. :-)

The week in qooxdoo (2009-06-19)

One thing about web development many of us like most nowadays is its constant, sometimes rapid progress. The comprehensiveness and performance of tools and technologies is exciting to watch (and even more exciting to advance actively). Anyone remember how the web stalled after the dot com bubble burst and the browser war ended in a browser monopole? Well, nowadays one can hardly be a few weeks off on vacation without missing many cool web-related happenings: Safari 4 final, Firefox 3.5 RC1, Google Chrome 3 beta (also for Mac OSX and Linux), Opera 10 beta1, and so on. Well, but lets see what exciting things a week in qooxdoo brings:

Flash widget

We finished its migration, so a Flash widget is now available again. The only known limitation is that the Flash movie is reloaded when the movie is being hidden and then shown again. A corresponding bug report describes this browser specific behavior. We try to find a solution for this, and let you know about it asap.

The demo browser shows an example of two-way communication using the External Interface.

Global Error Handling

This week we added the possibility to register a global error handler. The global error handler is called for all exceptions, which have not been caught by the application code. This can be used to gracefully handle runtime errors, which is crucial for a truly professional web app. There was just a separate blog post published with the technical details.

Code Coverage

When implementing test-driven development (TDD), which we try to do for most of the newer framework developments, e.g. the data-binding layer, code coverage is something to think about. We asked ourselves how to get something into Testrunner for some quantitative analysis. As a first prototype we came up with a solution, which marks a method as "tested" if it has been invoked at least once during a complete unit test run. Of course, this is rather a coarse approximation of code coverage, but nonetheless it can at least give you a hint about what to look at that you missed completely. The prototype nicely utilizes qooxdoo's built-in support for aspect-oriented programming (AOP).

If you have any ideas or suggestions regarding code coverage, feel free to post them as a comment to the code coverage bug report. This bug report also has some more details on how you could extend testrunner for this experimental dev tooling.

Generator

Work as been continued on a deep dependency analysis for qooxdoo classes, which tries to collect load-time dependencies introduced e.g. through static method calls used to initialize class members and properties. It is still highly experimental. To play with the feature, the config key
dependencies/follow-static-initializers : true has to be used. But the process currently chokes on circular dependencies, so you cannot use it in production.

Snippets

A new snippet describing how to reduce the requests to your backend when using the Remote Table Model has entered the snippets section. Give it a try!

Bugs

For a complete list of bugs fixed during the last working week, use this bugzilla query.

Documentation

Following up on the work on contribution templates last week, the wiki page about adding a contribution has been reworked, casting out all qooxdoo-version dependent information to the relevant manuals, among other things.

Demo Hosting

People were reporting difficulties to access the online demos running on a non-standard port since recently, e.g. due to corporate firewall policies. Also, some browsers drop the fragment identifier of URLs after a redirect. We are working on an improved solution and hope to bring back the online demos at a standard port and without redirection any time soon.

That's it for today. See you next time.

Global Error Handling

In object oriented programming it is common practice to throw exceptions for known error conditions. However, JavaScript lacks one essential feature to make consistent use of exceptions practical: There is no way have a fallback handler, which receives all exceptions that are not caught in the application code. The result is that uncaught exceptions show up in the browser and depending on the user's preferences might even pop up an error dialog. Furthermore, in production systems it is often desirable to log all errors and send them back to the server to monitor the application.

Most browsers provide the window.onerror hook, which is supposed to act as a fallback error handler, but since it is not standardized, the implementations differ significantly.

 
window.onerror = function() {
  console.log(arguments);
  return true; // hide error from browser
}
throw new Error("Error");
 

onerror_firebug

Note that only the error message but not the exception object is available. The second and third parameters point to the URL, which raised the error and an error code. Both additional parameters are missing in Safari. Opera doesn't support onerror at all.

Since we can't rely on onerror, we decided to provide our own implementation of a fallback error handler. The basic idea is to wrap all JavaScript entry points with a try/catch block and call a predefined error handler on all exceptions. An entry point is a function, which is called directly by the browser. DOM event handlers or callbacks passed to window.setTimeout or window.setInterval are such entry points:

 
qx.event.GlobalError.setErrorHandler(function(ex) {
  console.log(ex);
});
 
window.setTimeout(qx.event.GlobalError.observeMethod(function() {
  throw new Error("Error");
}), 100);
 

globalerror_firebug

This time the error handler receives the real exception instance and not just the error message. qooxdoo already abstracts most of this low level event handling code so users won't have to bother with wrapping their own methods (e.g. when using qx.Timer instead of a native window.setTimeout). For example all qooxdoo event handlers are already wrapped.

The implementation of observeMethod is a variation of a technique first documented by Nicholas Zakas:

 
observeMethod : function(method)
{
  if (qx.core.Setting.get("qx.globalErrorHandling") === "on")
  {
    var self = this;
    return function()
    {
      if (!self.__callback) {
        return method.apply(this, arguments);
      }
 
      try {
        return method.apply(this, arguments);
      } catch(ex) {
        self.__callback.call(self.__context, ex);
      }
    };
  }
  else
  {
    return method;
  }
}
 

The wrapped method is only enclosed by a try/catch block if an error handler is defined and the setting qx.globalErrorHandling is enabled. This is an important detail because the try/catch block can mess up the stacktrace and thus make the code harder to debug. In these cases the "normal" behavior can be restored by simply setting the error handler to null.

The global error handling is a replacement of the dysfunctional window.onerror and will be part of the next qooxdoo 0.8.3 release.

HTTP Redirects and Loss of Fragment Identifiers

Have you tried a demo URL like http://demo.qooxdoo.org/devel/demobrowser/#widget~Label.html lately? We use fragment identifiers (or anchors, if you prefer) to select specific demos within the Demobrowser, as the widget/Label demo in this case. Those URLs can be bookmarked, sent around, and appear in the browser's history so you can go back and forth between them using your browser's history navigation devices.

After we have off-loaded our demo subdomain to a different port, the main web server redirects requests for demo URLs to that port, and the client fetches the application from the new location. But as it turns out, some browser don't keep the fragment identifier across the redirect. While Firefox3 and Opera9.6 handle fragments just fine, IE7 and Safari4 choose to forget the fragment after the redirect, so you end up with the Welcome page in the Demobrowser instead of the Label demo. Funnily, all browsers send the request URL without the fragment id, so there is no difference here, and consequently there is no way of dealing with the fragment on the server.

I did a bit of research on the Internet, but there doesn't seem to be much concern about this behaviour. There is an hopelessly expired RFC draft which at least addresses the issue. But apart of that there is not much discussion which appears odd to me. I figure it would be a quite common situation where you have a large document with several anchors, and then the document might get relocated on the server. Now all URLs specifying one of those anchors would put you at the top of the document in half of the browsers, which is a serious loss of information.

This week in qooxdoo (2009-06-12)

Another (short) week here in Germany at the qooxdoo headquarters. Since yesterday was a public holiday in some states here in Germany some of the qooxdoo core developers took the opportunity for a long weekend.
Anyway: here is the report for this week.

Framework

RadioGroup

The old implementation allowed an empty selection, when calling for example the resetSelection method. After the execution of this method no item was selected.
But there are use cases which need to have one item always selected, so we had to find a solution to support those. Since the original behaviour couldn't be changed because other widgets rely on it, we introduced a new property allowEmptySelection to fix the Bug #2297.

The new property allowEmptySelection can be used to configure the behavior of a RadioGroup. To allow an empty selection just set the property to true.

Bugs

Support for displayName in Webkit

To gain a better debugger and profiler support we introduced the support for the displayName property on function objects. This greatly enhances WebKit debugging/profiling of qooxdoo applications. See Bug #2359 for more details.

Complete list of fixed bugs

For a complete list of bugs fixed during the last working week, use this bugzilla query.

Tool Chain

Cross-Drive Setups on Windows

We had several issues on Windows if resources needed to be referenced in the application using absolute paths ([1], [2], [3]). This could happen when the resources where on another drive, or the TMPDIR macro would be used (as it resolves to an absolute path on Windows). It was also unclear how these paths would be best encoded when used as a URI.

This has been addressed, and now it is possible to distribute your qooxdoo setup across local Windows drives. For example, you can unpack a qooxdoo SDK on one drive and create and work with an application on another. E.g. you can do something like this:

C:\qooxdoo\tool\bin>create-application.py -n gui -o D:\Projects

This also affects the new cache default directory and contributions which are downloaded into it, which is beneath your %TEMP% directory, and referenced in the application with their full path, including drive letter. This also works now.

Contribution Skeleton

create-application.py offers a new template, the contribution skeleton template, activated with the -t contribution command line option. Its purpose is to make writing qooxdoo-contrib contributions easier. It's best used in the root directory of a local qooxdoo-contrib SVN checkout. Then you get immediately the right folder structure in the right place. Things are still a bit in flux, and there will probably be a longer introduction to this skeleton at a later time. But as usual, early adopter feedback is welcome.

Contributions

SkeletonWidget

The SkeletonWidget sample contribution has been enhanced to work with qooxdoo 0.8 (0.8.3-pre, to be exact). The 0.7-compatible version has been moved to the 0.7 directory, and trunk now contains the 0.8-compatible version. Since this was intended as a template for new contributions, this use case might be better fullfilled by the above mentioned contribution skeleton (which, in contrast, saves you from a bit of typing). But it's still in, and Thomas is using it for testing contrib:// style library inclusion in applications, and that's why he fixed it in the first place :-) .

HtmlArea

Since we encountered a bug within the 0.3 and 0.4 version we decided to open up a new branch 0.5-pre for users of the 0.7.x based HtmlArea component. Users who use the 0.8 based HtmlArea can stick with the trunk version to obtain the fix.

Test Driven Development for User Interfaces

Test driven development (TDD) is one of the central techniques in Extreme Programming. However many people dismiss it for GUI applications because it seems to be too hard to get the user interface code under test. Last Friday I did a presentation in our office about how to apply TDD to GUI applications. I used the the calculator contrib as example application. The slides are still German but I could translate them if there is enough demand for an English version.

Update:
Due to popular demand here the translated English slides:

The week in qooxdoo (2009-06-05)

Greetings, qooxdoodians! Time for another weekly report - let's jump right in. With several core developers away from the office, and an internal conference that took place, there is not much to report this week.

Framework

Documentation

There is a new document on source file structure, which contains the (so far unndocumented) list of possible compiler hints for 0.8.

Bugs

For a complete list of bugs fixed during the last working week, use this bugzilla query.

Generator

Cache Stuff

Following a lively discussion on the mailing list, create-application.py now takes another command-line option, --cache <path>, to  indicate the cache path. The skeletons all have the CACHE macro in their let sections, which will be  filled by create-application.py. If --cache is not specified , the default value will be ${TMPDIR}/cache, as it currently is.

Documentation

There is a new document listing the pre-defined macros for the generator.

Contributions

Simulator

Simulating mouse clicks on specific cells of qooxdoo tables with the Simulator contribution used to be pretty impractical: The qxClick command allowed clicking on a specific set of coordinates within the table pane - but which cell happens to be at a given position depends on the table's current scroll position as well as its content, making it all but impossible to click on a specific cell.

This changed thanks to qooxdoo user Mr. Hericus who contributed some very useful code to the Simulator's qooxdoo user extensions and language bindings:

  • The qxTableClick command sends left, right and double click events to a specific table cell.
  • The qxObjectExecFunction locates a qooxdoo object, calls one of its functions and returns the result.

Soap Client

Burak Arslan has released v0.4.1 of the soap contrib. Burak announced it on the mailing list:

"a maintenance release for the soap client is released. it includes miscellaneous fixes to bugs caught by my and will pritchard's tests. following the fixing of bug 2369, it works also on internet explorer. the only thing that's left to do is to integrate qx.io.remote.Request instead of managing the xmlhttprequest object directly."

So much for today. Next week will be a short week again for us, which might result in an early issue of the weekly - we'll see. But for now, have a good time.

Generator and Unicode Application Name Spaces

This is another post in a loose sequence of articles around I18N  and Unicode support in qooxdoo, and qooxdoo's tool chain particularly. (The other so far were 1 and 2).

Wesley Chun writes in his excellent Core Python Programming in the section "Real-Life Lessons Learned" about adding Unicode support later to a system

"The retrofit of the entire system would be extremely tedious and time-consuming." (p.203, 2nd ed.)

and later adds

"Fixing Unicode bugs everywhere leads to code instability and the distinct possibility of introducing new bugs." (p.204, 2nd ed.)

You might not be surprised to hear that my experiences largely match his statements.

Using a unicode name space

This time, I started off by using a name space for a qooxdoo application that contained real unicode characters. To create the project, I did something like this:

create-application.py -n höräßlich

(Don't worry about the name space, it's a made-up word that contains three "funny" characters).

There are two main areas where the name space of an application makes its mark:

  1. it is inserted into various source files where the name space of the application is needed, e.g. in class files, in the first parameter to qx.Class.define().
  2. it is used in the file system, to create proper paths to the class files (as in .../source/class/<namespace>/....), to resource files, asf.

I had to tweak create-application.py a bit, but after that the resulting skeleton application looked just fine. Then I invoked generate.py source, and that's were the real trouble started...

The generator has to deal with the exact two areas for unicode name spaces as listed above. Text files are read and processed, and there is interaction with the file system which always involves paths where the "funny" name space is part of.  I was confident that the text file handling would be consistent, since we read and write all text files as being UTF-8 encoded. But there was no such consistency regarding file path handling, which showed after I followed and fixed exception after exception popping up in the generator. Then I sat back to think about the issues from a general perspective. All critical code sections involved strings that now contained unicode characters which were not accounted for, either when doing operations on them, printing them, or passing them into module functions. The cure was almost always decoding the string from UTF-8. So I thought whether there would be a single or a few general approaches to the issue...

sys.setdefaultencoding()

The sys module of Python has a nice function, setdefaultencoding(), which allows you to switch from the default ASCII to other encodings such as UTF-8, which the Python runtime will use whenever it has to decode a string buffer to unicode. And I'll tell you what, I switched to UTF-8 and it worked like a charm! But there is a catch: You can't use this function in your application code, seriously :-( . This function is only available at Python start-up time, when Python scans the environment. It has to be called in a system-wide module, like /usr/local/lib/python2.5/site-packages/sitecustomize.py, where sitecustomize.py is a pre-defined name (you cannot make it up). After this module has been evaluated, the setdefaultencoding() function is removed from the sys module. There is no way of using it afterwards. Isn't that weird?! So I had to go on and look at the various places where we deal with strings in the tool chain.

String Literals

One aspect of the issues are string literals. So what about changing all string literals in all tool chain modules to Unicode strings?! That looked like a safe path to ensure we are treating unicode strings in any place. It turns out that the tool chain in total uses more than 13,000 string literals (gasp!). That was, um, more than I expected. Given the fact that all those strings have to be represented in memory at run time, there seems to be some opportunity to improve memory footprint here. But that's a different issue.

But concerning unicode support, whatever memory footprint our string literals have, converting them all to unicode strings would double this footprint. Currently, we only have ASCII string literals that use one byte per character. Turning these into unicode would result, at best, in each character being represented by two bytes in memory, since Python normally uses UCS-2 internally to represent unicode. - I didn't need any more estimates to figure that that would be carrying it too far.

So we're back to handling and converting strings on an individual and per-case basis.

The os module

Another aspect of unicode treatment are the Python modules we use. The os module is all over the place in the tool chain. The important discovery here was that the methods returning strings can often be parametrized in a helpful way. Take os.listdir(): If called with a normal string it will return an array of strings. If called with a unicode argument, it will return unicode strings. (Try calling os.listdir() with a normal string representing a directory that contains unicode entries, either files or subdirectories. On Linux the returned list will contain those entries in UTF-8. On Windows it actually looks like UCS-2 encoding, the same encoding Python uses internally. But now try to decode a UCS-2 encoded string into an internal unicode string - you'll be surprised).

This sort of polymorphic behaviour holds for similar functions like os.walk() and os.path.join(). os.getcwd() can be replaced by os.getcwdu(), in order to obtain the current working directory as a unicode object. So I will crawl over the code base eventually and look at each line the os module is called, rectifying parameters or switching to unicode-enhanced functions.

... to be continued

And that's not the end of the story. Uses of other modules have to be inspected, corrected, and calls to their functions possibly be flanked by unicode de- and encoding actions. While file I/O should be fine, terminal I/O might not, so calls to print and <stream>.write() will have to be inspected. Platform-dependencies might come into play. And how to obtain unicode command line parameters...

Next Page »
 

Control

 

Categories:

Archives:

 
SourceForge.net Logo

Bad Behavior has blocked 398 access attempts in the last 7 days.