Personal tools
You are here: Home Weblog rants

rants


2010-02-25

Can you do this on your shiny Mac?

Filed Under:

Probably you can, but you have never done it because you have a shiny interface for everything. I'm talking about this discovery of mine:

svn diff | kompare -

What it does is to take the output from svn diff and pipe it into Kompare, a merge/diff utility from the KDE Project. I can do this from the command line, straight from the directory that I'm in, and bang! I get a nice graphical overview, complete with the tree structure that I can navigate to see what I'm about to commit. Honestly, this little command gets me excited everytime I run it.

2010-01-28

Another cause for buildout failures: system distributed Python

Filed Under:

Always compile your own! One day I'll even remember that...

I've had a buildout bootstrap process failure, this time a weird one, perhaps I should document the bug and report it.

The latest Ubuntu version which I have installed (Lucid Lynx) comes with a package called python-pkg-resources, which packages pkg_resources, which used to be available only through the setuptools distribution. Buildout's bootstrap.py tries to guess if Setuptools or Distribute are installed by checking the availability of pkg_resources; by guessing wrong it all comes to a crash at the end.

I'm not very interested in debugging these types of problems anymore. Distribution/packaging tools should just work. I want to focus on my work, not debug the toolchain. No more corner cases or whatver. So I'm gonna compile separate Pythons in the future, especially when dealing with older Zope/Plones.

Dear PyPi uploaders: don't use a download URL, upload your package instead!

Pypi's biggest mistake: allowing package entries without any upload

I think this is the Python Index biggest mistake, the one which makes it unreliable for serious development environments: exposing package entries with no real package files and just a download URL. To see what I'm talking about, just examine the PyPI records for BeautifulSoup or IPython, packages that are very common in buildouts. As soon as the author and publisher of that package has a hosting problem, the developer that uses that package also has a problem. Buildouts will completely fail and this will cause dead times and frustration for the developers.

Yes, there are a couple of PyPi mirrors, but they only mirror files hosted by PyPi. The central PyPi site will probably have better performance and availability then what individual groups and developers can provide and it's always easier to mirror one single website than many, so there's no shame or loss of pride in using the PyPi to host your files. Please do so!

 

2009-11-30

A "don't do" for internationalizing Django templates

Filed Under:

I'm internationalizing a Pinax website and I've encountered this piece of code in a template:

<input type="submit" value="{% trans "invite" %}"/>
{% blocktrans %}{{ other_user }} to be a friend.{% endblocktrans %}

The message ids for this code would be two separate blocks: "invite" and " %{other_user}s to be a friend". Both offer very little in terms of context and make the translators job difficult. Correct, in my point of view, would be the more convoluted form of:

{% blocktrans %}
<input type="submit" value="invite"/>
{{ other_user }} to be a friend.
{%  endblocktrans %}

This implies that the translators know enough HTML to notice that the value attribute needs to be translated, but the end result is a lot more flexible and provides real context to them.

TL;DR: don't split paragraphs into separate translation units. It's a NO-NO.

UPDATE: I have found what is probably the worst example of how to create a translatable template. Remember, don't assume the English language resembles anything like another language.

{% trans "edited by user" %} {{ obj.editor.username }} {% trans "at"%} {{ obj.modified|date:"H:i" }}

This should be done this way:

{% blocktrans with obj.editor.username as editor_username and obj.modified|date:"H:i" as obj_modified
edited by user {{ editor_username }} at {{ obj_modified }}
{% endblocktrans %}

Odd thing in Django: the date filter takes PHP as reference instead of Python

Filed Under:

I wonder what possible explanation there is for the behaviour of the date template filter.

Uses the same format as PHP's date() function (http://php.net/date) with some custom extensions.

I understand where Django comes from, but I think this sort of things should be more aligned with the rest of the Python world.

2009-11-18

If Django templates are an improvement over XML templates, then, by all means, please give me XML

Filed Under:

I fail to see how

{% block %} 
...
{% endblock %}

is in any way better or "less scary" then, let's say

<dj:block>
...
</dj:block>

Yet another rant, this time triggered by the error I got when writing this piece of code:

{% blocktrans with offer.offerer.username as offerer_username 
               and offer.offered_time|date as offerer_date %}
...
{% endblocktrans %}
I just wanted to split the tag on multiple lines, but it seems that's not possible. If Django templates would have been XML, then it wouldn't have been any problem formatting that piece just how I want it. Right now, the joined line takes two times the amount of my screen width.

One more thing to grudge about is that vim, even with djangohtml syntax type installed, is not very knowledgeble about how to format the template file (it treats the tags as regular piece of text). Probably this could be fixed, so I shouldn't complain about this too much.

I think Django templates are compiled to python code, so it's natural that they're treated in an imperative, dumb way, but that's not the only way of doing things. For example, Chameleon is another templating library that compiles its templates as python code, has no problem working with an XML based templating language frontends.

2009-11-17

The case against Django templates

Filed Under:

I have many grudges against the django templating language and its templates (in short, I hate them), so I'm gathering evidence to support what my "spider sense" tells me. Today the template tag system goes under fire.

Given the following template fragment:

{% load i18n %}
{% load avatar_tags %}
{% load voting_tags %}
{% load pagination_tags %}
{% load extra_voting_tags %}
{% load in_filter %}
{% load extra_tagging_tags %}
{% load sorting_tags %}

Which one is responsible for the following "anchor" tag?

{% anchor "hotness" "reddit-like hotness" %}

That's the equivalent of diving into a python module, with lots of "from X import *" at the top. Where do you find the definition of a symbol? At least, if it were Python, I could do a tag search in Vim, or a "go to definition" in Eclipse. If this practice is frowned upon in the rest of the Python world, why are so many programmers praising the Django templating system? Am I the only mad man here? My problems with this tag is that it doesn't translate the content, so I'll need to grep for its source and change it.

The template tags in Django are about extending the templating language, as to provide the programmer with new and specialized ways to interact with the template and its environment. The reason for this "tag inflation" is that the django templating language, for all its richness (by tags and filters numbers, I mean), is really limited. Python expressions are not allowed, and for every imaginable use case, there needs to be a tag, specialized or not.

How would Zope 3 solve, for example, a problem similar to the one the "anchor" tag handles? Well, rendering a special link for a content item could be as easy as

<a href="" tal:replace="someobject/@@hotness_link"><img src="hotness.gif" /></a>

Is this better? I think so. I'm editing HTML, and the <a /> tag is way better in expressing what the end result will be, compared to a simple {% anchor %} tag. Even more, the <img /> tag inside is purely cosmetic, just to cue the viewer of what the final result will be. The entire <a /> tag, with its content, will be replaced by whatever result is rendered calling the the someobject/@@hotness_link view. Finding the source of the hotness_link view is easily introspectable TTW using a debug tool such as lovely.skinbrowser.

The ZPT templates from Zope 3 can also give you a mechanism where you can add new expression types, but there's just one or two packages in the wild that define new expression types. Now compare this to the regular Django projects, were defining new tags is something that almost all projects do.

In conclusion, even though Django templates are much more imperative then ZPT, which are very declarative, they don't achieve the power and simplicity that they strive for.

2009-11-12

Django's makemessages sucks for my use cases

Filed Under:

Yet another angry rant, caused, of course, by using Django in anger. Nothing wrong with using something in anger, that's the real way I learn something. Zope 3 even has an online book on how to use it in anger.

That said, Django's makemessages administrative command sucks by being way too inflexible to anything but the ideal Django development environment. My environment looks like this: I have a project based on Pinax, which I'm developing and deploying using zc.buildout. My source code sits in src, where I have several packages. I also have a "localsettings.py" module located in the root of the buildout, because I don't want to have it inside the src folder. Pinax is located in parts/Pinax, and it's actually a git checkout, based on my own fork of Pinax. Pinax doesn't have translations at the moment (I think I saw a ticket in its tracker about reintroducing a translation package), so I'm on my own here with regards to translation.

With this setup, it is close to impossible for me to generate anything useful without a lot of hacking and swearing. Makemessages insists on being run from inside a Django project, and when I did that, it complains about missing localsettings module. Pointing the root of the buildout as pythonpath didn't do anything. A good thing that I have already extracted messages from the templates, before switching to the buildout project structure.

Some solutions that I have found:

  • I can extract messages from the Pinax python modules using this homegrown script:
PYFILES=/tmp/pyfiles
PINAX=parts/Pinax/pinax/ 
BASE=/home/tibi/work/ProjectBuildout/src/project/locale/ro/LC_MESSAGES/
POTFILE_PYTHON=$BASE/python.pot
POTFILE_TEMPLATES=$BASE/templates.pot
POTFILE=$BASE/django.pot
POFILE=$BASE/django.po

#extract messages from python code
find $PINAX | grep ".*py$" > /tmp/pyfiles
touch $POTFILE_PYTHON
xgettext -j -L python -d django -f $PYFILES -o $POTFILE_PYTHON

#merge the templates + python messages into one pot file
msgcat -o $POTFILE $POTFILE_TEMPLATES $POTFILE_PYTHON

#merge the potfile with the po file
msgmerge -U -N $POFILE $POTFILE
  • I have copied all the templates from pinax and its associated applications inside a template folder in my project. Now I can generate the po file, from my src/project folder, with
../../bin/py ./../../manage.py makemessages -e .py -e .html -l ro

Of course, I can't run this over the other apps and packages in my src/ folder to extract messages from the python modules, so I am forced to adjust the first script to take those folders into consideration.

2009-10-07

Questioning the quality of code in Django third-party projects

Filed Under:

I'm not sure how I feel about this... In some ways, I think it's very positive that a relative newcomer can just jump in and release an opensource project that can be taken and reused by others. Did Django allowed this? That's very positively PHP-like...

I'm talking about a glimpse at some code that I caught while helping my brother integrate the Diamandas forum to a site he's doing. It stunned me that it has the marks of a developer that is not very experienced with the language or the framework, but it's moving at a speed that is too great to stop and fix or check what he's doing.

This:

pr = False        
if forum.use_prefixes:                
    p = Prefix.objects.filter(forums=forum)                
    if len(p) > 0:                        
        pr = []                        
        for i in p:                                
            pr.append(i)

is a fragment from an apparently nice Django forum add-on. First, it could easily be rewritten as:

pr = []
if forum.use_prefixes:
    pr = Prefix.objects.filter(forums=forum)

Suppose you don't trust the Django queryset results to really behave like a list (that could happen for some legitimate reasons, but I'm sure that's not the case here). Then you could write the last line as:

pr = list(Prefix.objects.filter(forums=forum))

Of course, no more lazy loading of objects and a bit more memory consumption. More, about the looks of this code:

  • "len(p) > 0" can be rewritten as "if p"
  • why define the "pr" as a False value instead of an empty list, which will become at one point?
  • why use the "i" name for a prefix object type, when this is typically used as an integer counter?

Further on that page there's

tp = TopicPrefix(topic=new_place)
tp.save()
tp.prefix=pr
tp.save()

I haven't tried this, but I'm pretty sure that only one call to save() is needed. Probably more odd things could be found, but I haven't tried to look further - I already found the source of my brother's problems.

These superficial aspects are the ones that make me also question the architectural choices that were made for this add-on, the overall quality of the code that might impact performance, etc. How can I trust an application that has bits of code like this? I'm pretty sure that this particular developer (I haven't bothered tracking exactly who it was) has a bright future in the Django community and will probably polish his Python skills to generate good code. Overall, the Python and Django communities will also benefit from an influx of new developers. But I'm left feeling insecure about my decision to write code for the Django platform. I'm mostly (or I want to be) an integrator and I depend on good third-party addons, which Django seems to have a lot. But if two out of three projects that I have tried (Satchmo and Diamandas) left me confused, how else should I feel? Ironically, the one project that I have really liked (LFS) came from a Zope developer... So maybe we need a bigger Zope > Django migration phenomena.

UPDATE: well, it looks like Django isn't free of promoting (IMHO) stupid solutions, too. Check out this piece of code from the Django admin documentation:

return self.birthday.strftime('%Y')[:3] == '195'

This smells a lot like stupid code that beginner PHP programmers would write. When you're dealing with a number (the year), why convert it to a string? The code itself yields correct results, but the method used feels stupid. I'd rather see something like:

return 1949 < self.birthday.year < 1960

Another one, not a bug, but a design decision from Django, which forces third party projects like Pinax to mangle with the syspath just to get django happy:

  File "/home/tibi/work/lib/python2.5/site-packages/django/contrib/auth/models.py", line 283, in get_profile
    app_label, model_name = settings.AUTH_PROFILE_MODULE.split('.')

What's my AUTH_PROFILE_MODULE set to?

AUTH_PROFILE_MODULE = 'pinax.apps.basic_profiles.Profile'

Actually, thinking more about this: "pinax.apps.basic_profiles.Profile" is not even a real path, Profile is a class in "models.py", so it might be valid for Django to request its special rules there. Valid, but non-intuitive and non-standard for the rest of the Python world.

Another weird stuff, this time in Pinax. Looks like really young code, which hasn't been subjected to a thorough code review yet: friends_app/views.py. This is file has some weird indentation problems (some lines get indented more then they need to be). What about this piece of code:

authsub_token = request.session.get('authsub_token')
del request.session['authsub_token']

If 'authsub_token' is not in the session, (as it was my case, which made me discover this), you'll get an error on the second line. Of course, this bug highlights the more important problem, of the missing authsub_token, but what about the careless programming?

2009-09-17

Customizing Django LFS (Lightning Fast Shop) for the non-django developer

Filed Under:

I'm not a Django developer, but I have a project that involves deploying a LFS site, and it took me a bit of time and effort to understand how to customize its templates and resources. This all may seem obvious to the any Django developer, but I'm not, so I think this info needs to be out there.

As a side note, at first I have reviewed Satchmo, as it seemed to have more traction in the Django community (being a Zope/Plone developer, I am more aware of the previous work done by the LFS developer, the EasyShop). The Satchmo installation, for the un-initiated, seems to be a nightmare of many different settings that needed to be tweaked, skeletons that don't work OOTB, at least in the way I have installed them. On top of all this, it seems to think that I also need to develop some sort of project that will integrate with the Satchmo shop (but this may be due to Django). What happened to treating your product as the end product? After a bit of effort, I had one instance running and ready to review it. Several days, in another Linux virtual machine (I've switched from VMWare to VirtualBox), I've tried to install Satchmo again, this time using djangorecipe. I didn't have the same patience, though.

A short look at LFS convinced me to at least give it a try: there is a buildout that can be installed easily (although there were a few dependencies that I had to install), the "backend" is polished compared to the default django admin views used by Satchmo, and, while it is simpler, less featured, than Satchmo, it does everything I need.

Onward to customizing the LFS: my goal is to be able to change templates (for example, the base layout) and publish a new logo.

I've created a new folder "mytheme" inside the buildout, with two subfolders: "templates" and "static". The path to the templates folder needs to be inserted in the "TEMPLATES_DIRS" variables from settings.py. To customize the base template, for example, I've created a "lfs/base.html" file inside the "templates" folder. Its content can be copied from the original in the lfs_theme folder. I've added a new line in the header section, pointing to a new CSS file that will customize the base LFS stylesheet.

<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}mytheme/css/custom.css" />

As a side note, this templates folder can be used for overriding any other template: templates in Django are usually denoted by a relative path, and you need only to replicate this path inside our overriding templates folder.

Next, overriding and creating new resources: I have created a "static" folder inside "mytheme" and I've linked to it inside the lfs_project/media folder. Inside the "mytheme" folder I can now host images and files, in 2 new "css" and "img" subfolders. Back in my customized base.html, I have changed the logo path:

<img class="logo" src="{{ MEDIA_URL }}mytheme/img/logo.jpg" alt="Logo" />

That's about it: I got a custom CSS, the ability to customize templates and to point to new images. I'm happy for now.

As I have said in the beginning, this is all basic stuff. No harm done in pointing to the obvious though, as there seem to be many new developers flocking to Django, all with different level of expertise.

2009-08-05

ReportLab is one frustrating piece of software...

Filed Under:

I'm starting to grow a strong dislike to it, enough to steer me off Python to JVM, with Jython or Scala. Case in point: its authors considered that it's appropriate to overload the Paragraph class from the platypus module, to make it accept a form of "xml". There's no switch to disable this behavior and its xml handling is something straight out of the 90's: no namespaces, no validation. What happens for example, when you're trying to make a paragraph with the text:

 "Some html documents contain <img> tags"

That's right, you'll encounter an error. The "<img>" fragment is interpreted as an img tag for the Paragraph, which will then complain that it's missing a src attribute. I wonder how can ReportLab be promoted as an enterprise solution and still display this behavior. The easiest solution, in my opinion, would be to create a new class that accepts properly formated xml, and RL's special tags need to be isolated in a new namespace. Fortunately, for the time being, I can do a replace for the "<" character with the &lt; entity.

2009-06-11

Laughable bug in a new Google Webmaster Tools feature

Filed Under:

Somebody at Google has screwed up in a laughable manner. Webmaster Tools just got a new feature: the ability to tell Google that you have moved a site to a new domain. I'm in the same situation with one site that I manage: www.caleidoscop.org.ro has been moved recently to www.caleidoscop.org. Although I have done my best (I still need to persuade nginx to generate 301 redirects instead of 302) to ease this transition and absolutely everything pointing to the .org.ro  is redirected to the .org address, Google is really slow in picking the change and the Webmaster Tools show links from caleidoscop.org.ro as the main source of links to the new .org domain. Unfortunately, as things stand now, it's impossible for me to use this feature: Google doesn't recognize *.org.ro as being a "root level domain", as can be seen in the next two screenshots. I wonder, org.uk domains have the same problems?

 

First, the bug

Bug in Google Webmaster Tools


And this is how it's supposed to look

This is how it's supposed to look

2009-05-10

My new blog dedicated to all things VIM

Filed Under:

I've opened a new blog, at http://vimzone.pixelblaster.ro It runs on the latest Plone 3, with the NottreDamme skin and Scrawl as the blogging product. I'll probably install also the QuillsEnabled extension. There's not a lot of content on it, although it's already almost 2 months old. It's a place for me to scribble things I know about VIM and use or discover.

2009-04-16

The sorry state of internationalization in Plone

Filed Under:

Ever since Plone 2.5 stopped being the hot new thing in the Plone world, the state of content internationalization support in Plone has been declining. Partly due to the difficulty of extending Zope 2 products, LinguaPlone has always been a hack, but at least back then it worked. These days I'm not heavily involved with Plone, but whenever I need to add LinguaPlone to a Plone 3 site, I cringe and weep, especially that those projects never allocate time for me to fix the obvious problems. Some of those problems, in current Plone 3.3 rc2 are:

  • the flags are no longer grayed to indicate that a certain translation is unavailable
  • the switchLanguage script doesn't work anymore, it won't redirect you to the translated content; the LanguageTool is broken (won't take VHM into consideration) and an update was released, but the versions.cfg file on plone.org hasn't been updated yet, so you need to add a [versions] section, with the correct specification for the Products.PloneLanguageTool
  • the changeLanguage script was removed, in favor of doing a direct translation. Wops, now it's possible to translate into neutral, which gets you fast into an ugly traceback that you won't be able to get rid of.
  • the language neutral behaviour for fields is broken. Example: I have a content type with the neutral fields, when translating a content item the content of those fields is erased. This is something that I'll have to fix.

On the upside, the translation management mechanism (after some hickups) has improved.

I don't have access to the Plone subversion. I already had some discussions with two of the developers that have done the latest changes to LP, but they either didn't understand the problems or didn't have time to do the fixes themselves. To make it easier for myself and stimulate my interest in the LP development, I have copied the latest LP trunk to Collective, in a location called Products.LinguaPlone-Unofficial. This version also has a check for the case when there's a translation into Neutral, so it should fix the error detailed above.

Update:

Another problems solved: I've wanted to be able to switch languages based on the subdomain (ro.site.com, en.site.com), which should be supported by the PloneLanguageTool, but didn't work for me. Digging down, I found the problem: plone.i18n.locales.cctld has a list that associates TLDs to languages, but most of the TLDs don't have a language associated to them! This issue should be at least highlighted in the documentation for PloneLanguageTool.

One more weird problem, which caused me to blame LP for even more problems than it has at fault: upgrading as site from Plone 3.2 to 3.3 rc2 broke the LP language selector, by making the default Plone one override the LP one (where it should be the other way). I was able to solve the problem by customizing the template for the LP language selector (with no change)

2009-02-28

Success on a one year old problem installing CacheFu

Filed Under:

I've upgraded CacheFu (Products.CacheSetup) to the latest 1.2 for some of the websites that I manage, in a Plone 2.5 cluster. One of them had a problem that I haven't been able to track previously, due to limited time: on a reinstall of CacheSetup, due to product upgrades, CacheFu couldn't be installed anymore. The traceback was something like:

this product has already been installed without Quickinstaller!failed:
Traceback (most recent call last):

  File "/home/zope/z29/Products/CMFQuickInstallerTool/QuickInstallerTool.py", line 330, in installProduct

  File "/home/zope/p25/parts/zope2/lib/python/Products/ExternalMethod/ExternalMethod.py", line 225, in __call__
    try: return f(*args, **kw)

  File "/home/zope/p25/eggs/Products.CacheSetup-1.2-py2.4.egg/Products/CacheSetup/Extensions/Install.py", line 35, in install
    policy_utils.addCachePolicies(self, out)

  File "/home/zope/p25/eggs/Products.CacheSetup-1.2-py2.4.egg/Products/CacheSetup/Extensions/policy_utils.py", line 72, in addCachePolicies
    p.addCacheRules(rules)

  File "/home/zope/p25/eggs/Products.CacheSetup-1.2-py2.4.egg/Products/CacheSetup/Extensions/policy_2.py", line 13, in addCacheRules
    rules.invokeFactory(id=id, type_name='PolicyHTTPCacheManagerCacheRule')

  File "/home/zope/z29/Products/CMFCore/PortalFolder.py", line 408, in invokeFactory

  File "/home/zope/z29/Products/CMFCore/TypesTool.py", line 934, in constructContent

  File "/home/zope/z29/Products/CMFCore/TypesTool.py", line 343, in constructInstance

  File "/home/zope/z29/Products/CMFCore/TypesTool.py", line 574, in _constructInstance

  File "", line 6, in addPolicyHTTPCacheManagerCacheRule

  File "/home/zope/p25/parts/zope2/lib/python/OFS/ObjectManager.py", line 301, in _setObject
    v = self._checkId(id)

  File "/home/zope/z29/Products/CMFCore/Skinnable.py", line 223, in _checkId

  File "/home/zope/p25/parts/zope2/lib/python/OFS/ObjectManager.py", line 95, in checkValidId
    raise BadRequest, (

BadRequest: The id "httpcache" is invalid - it is already in use.

One other weird thing are the paths in this traceback: /home/zope/z29 doesn't exist anymore, the database was moved from a different server. I think it's related to the persistent product entries in the Control_Panels, which can be cleared. Not a big problem. In the log, there was also an entry related to this traceback:

2009-02-28 17:01:18 CRITICAL txn.-1223480432 A storage error occurred during the second phase of the two-phase commit.  Resources may be in an inconsistent state

Now, the solution is really simple, but I needed to debug the policy_2 module to find this: 

rules.invokeFactory(id=id, type_name='PolicyHTTPCacheManagerCacheRule')

didn't work because there was a document in the root called "rules". Nobody expects the spamish Acquisition! And I didn't either... Lesson? Zope 2 was designed to be too smart for its own good, thus violating the KISS principle. Still love it, though.

2008-12-03

Specific imports versus module imports in Python

Filed Under:

I've always been a fan of explicit, separate imports in Python, vs generic module imports. Maybe it's because I like things to be explicit, or I've been spoiled by the way Eclipse Pydev deals with auto-importing, but I have an aversion towards generic module imports. To keep the code style consistent, I even rewrite to this style any foreign code that ends up in my code.

Specifically, I'm talking about:

from foo import Bar
Bar()

vs

import foo
foo.Bar()

Needless to say, I like the first style better.

There are advantages and disadvantages for each of the above methods:

  • general module imports demand less from the editor (the programmer needs to type less "import" lines and the editor doesn't need to be very much aware of Python - emacs and vim users will probably favor this style)
  • but it makes it hard sometimes to figure out where a module comes from. Example: you're deep down reading a module and you encounter a line referencing the component module. Now, where does that component module comes from? Could be both of the following imports:
from zope.app import component
from zope import component

Of course, some people sensed this problem and write code like:

class MyView(object):
    template = zope.app.pagetemplate.ViewPageTemplateFile('template.pt')

But this code is hard to read, hard to write and is almost at the limit with the self-imposed line length of 80 characters, which means most of the times it needs to be broken in two lines.

Today I became aware of what I consider the biggest advantage of using specific import (from foo import Bar). Heavy refactoring, in the absence of a comprehensive test suite, is a lot easier! When starting the program, the imports will fail and you get an immediate pointer to where you need to make a fix. If I would have used a generic module import, the error will have appeared only when trying to use the piece of code that calls foo.Bar().

TL;DR: use specific imports! If your editor doesn't support it, take some time to look at Eclipse Pydev or Netbeans, two free IDEs with Python support. You'll get:

  • easier refactoring
  • better code legibility
  • I'll be happier when I need to reuse code snippets :-)

2008-11-23

Moving to Intrepid and KDE 4.1

Filed Under:

KDE 4.1 screenshotI've migrated my laptop (my main workstation, these days) and I've done a complete migration to the KDE 4.1 desktop. Things are not perfect, (on the old KDE 3.5 I'd say things were 99% according to my tastes), but I'm trying to accomodate and find replacements. I didn't like the KDE 4.1 launcher at first and I've even tested Launcelot for a while, but now I'm back to the default menu and I'm starting to like it (on 3.5 I was using Tasty Menu).

I'm using Scultptura style with the Scultura-Stone color scheme and Sculptura window decoration. I needed to add another plasmoid from kde-look, the panel spacer, to make the systray smaller and separate the buttons on the right side to those on the left.

Things that I'm missing:

  • no "window" list menu widget, which I've tried to replace with a plasmoid. I might as well remove it, because it doesn't list all the windows from all desktops, just the current desktop.
  • I don't like the double spacing of the clock & date widget, I wish that it was a single line. I saw that there's a plasmoid on kde-look.org, I might try that.
  • I don't like the black background in the systray (at the right top)
  • There's no working "app shortcuts buttons" plasmoid, although I may try to simulate that with the Quick Access plasmoid.

Things that I'm happy with:

  • Shiny new software!
  • KDE 4.1 is actually not that horrible, once I tweak it (although Kde 3.5 had the same problem, closest to my "visual" tastes comes Gnome, but I like Kde applications better).
  • NetworkManager seems to deal a bit better with my wireless connection (when my girlfriend opens her Macbook I get terrible disconnects from the access point)

2008-09-15

Stupid Internet Explorer and stupid IE bugs

Filed Under:

I'm placing the finishing touches on a web application I've been writing on and off for the last year. At last, I've reached Internet Explorer bugs, which are usually the last to be fixed. Among several other stupid but documented bugs, I've found one which I couldn't find documented in a shallow search on Google: it seems IE has an algorithm for comparing strings that is different then the one that is used internally when sorting an array of strings.

Take this code, for example, where I have separated the issue:

<html>
<body>
<script>

var x = [
  "Zwischenwasse",
  "Gurtis",
  "Götzis",
  "Partenen",
  "Raggal",
  "Rietz",
  "Schnifis",
  "Vösendorf",
  "Bludenz",
  "Galtür"
];

var y = [
  [34241, "Zwischenwasse"],
  [11223, "Gurtis"],
  [12321, "Götzis"],
  [12345, "Partenen"],
  [32454, "Raggal"],
  [34355, "Rietz"],
  [43453, "Schnifis"],
  [42321, "Vösendorf"],
  [43435, "Bludenz"],
  [43222, "Galtür"]
];

x.sort();
document.write(x);

document.write("<br/>");

var sorted = y.sort(function(a,b){
	return a[1] > b[1];
});

for (var i=0;i<sorted.length;i++) {
	document.write(sorted[i][1]+ ",");
}
</script>
</html>

The value which will be written in Internet Explorer when running this html document is:

Bludenz,Galtür,Gurtis,Götzis,Partenen,Raggal,Rietz,Schnifis,Vösendorf,Zwischenwasse
Bludenz,Galtür,Zwischenwasse,Gurtis,Götzis,Partenen,Raggal,Rietz,Schnifis,Vösendorf, 

Needless to say, in Firefox both lines will be the same, displayed in the proper order. On a side note, while I'm bashing Internet Explorer, let me just say that Internet Explorer 8 is a broken piece of software, at least on the side that I'm concerned. The developer tools are really buggy and tend to block the browser for even trivial operations (that is, when it doesn't crash it completely).

Update: apparently my mind is clouded with too much Python (I admit that Javascript is not a language that I use often). The problem is that the inline function used as sorting discriminator should return numeric values of -1, 0, 1, like this:

var sorted = y.sort(function(a,b){
	if (a[1] > b[1]){
		return 1;
	}
	if (a[1] < b[1]){
		return -1
	}
	return 0;
});

2008-03-28

Ubuntu Hardy Heron: some things are bad

Filed Under:

Note to self: always create a root account on Ubuntu.

I've updated my laptop to Kubuntu Hardy Heron, and while some things worked fine, there are a couple of stupid bugs that chained to make my life hard.

First of all, why did the Network Configuration applet in Settings Manager in KDE saw fit to delete the hostname of my localhost, tibi-laptop, from /etc/hosts? Now I can't run anything with sudo, as it imediately aborts with an error "No hostname tibi-laptop". Why can't my laptop find any Access Point if there wasn't one accessible at boot time? Why, when I've started Ubuntu in single mode, was I greeted with a dialog that asked me to select an option (continue normally, drop in root shell, fix X) but which didn't allow me to select anything (the keyboard wasn't properly recognized, even though that I have a perfectly regular keyboard on my laptop). Why does the reboot never finishes and maxes out the CPU?

The only way I could fix the hosts problem, while avoiding to hunt for some Linux cd, was to boot in Windows and install Ext2fsd and after that I was able to mount and change the /etc/hosts file.

These things are basic, they should just work. I'm aware that Hardy is beta right now and I'm using the KDE part of Hardy, but with Gutsy, (even though that applet always screwed up my network settings), I never had these problems. Shouldn't things go forward instead of backwards?

2008-03-19

Why do I use Zope 3?

Filed Under:

I'm in the process of beginning a new project and I'm debating on what framework to use. Of course it will be Zope 3, but why do I use it. Well, it's sure something that has to do with these facts:

  • it's open source, with a strong, mature community around it
  • while it's still actively development, it has a stable API
  • it's written in Python, one of the easiest and most powerful languages
  • it's built around a component architecture, which means writing pluggable applications comes naturally
  • solves the problem of publishing objects through the web
  • everything is transaction based. You won't lose data with it, you won't get garbage data inside your database
  • it has fast, configurable storages (ZODB, Relstorage)
  • internationalization and localization is easy
  • it's a library as much as it is an application server. When it's a library, it's very slim and as a full application server has a lot going on, including XMLRPC, ftp, webdav, sql connectivity, its own http server, etc.
  • has a cool, extensible templating language (the Zope Page Templates)
  • makes it extremely easy to create and store objects through ZODB
  • has facilities to query for objects using indexed data, through zope.catalog and extensions
  • writing a new catalog index is not an extremely complex task
  • it has an event framework; no complex application should run without an event framework
  • has advanced, flexible form libraries that can generate forms introspected from the models (zope.formlib, z3c.form)
  • has advanced templating concepts and content placement, such as the pagelets and viewlets
  • it's "enterprise ready": it's possible to load balance zope clients using ZEO or relstorage
  • comes with extensible authentication and user sources
  • promotes an extensible build system for applications (zc.buildout)
  • follows python standards, for the most part: library packaged as independent eggs and while it's not built around WSGI, it has full support for it
  • it can do document workflows (hurry.workflow)
  • it has some very cool packages from the community:
    • zc.table
    • z3c.form
    • Storm and sqlalchemy wrappers
    • zc.resourcelibrary, z3c.resourceinclude
    • z3c.pagelet
    • lovely.remotetask
    • grok
    • gocept.registration
    • z3c.traverser
  • is very well documented
  • it fits comfortably in my brain


Weblog
Atom
RDF
RSS 2.0
Powered by Quills
Technorati
Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: