Daniel Nouri's Old Blog

Note that this blog is discontinued. You can find my new blog here: Daniel Nouri's Blog.

Sat, 14 Mar 2009

Blog moved

My blog has moved over to http://danielnouri.org/notes/. Please update your bookmarks and stuff.

posted at: 21:47 | 0 comments | category: /misc rss | permanent link | add to del.icio.us or digg it

Mon, 02 Feb 2009

Shane's skinny based Plone 3 theme

Shane Graber writes me:

Thought you'd be interested in what I did with collective.skinny over the weekend. :) I grabbed an open source theme and whipped it together to see how easy it was and it was really pretty easy. :D

Note the over the weekend!

Here's the screenshot he sent me. You can click on it for a larger size:

Naturalist theme

Here's what he made it with: collective.skinny together with this theme.

Shane:

One interesting thing in this is that I've always wanted to somehow include smartypants.py and typogrify.py in a theme and with this theme I found it very easy to do.

posted at: 09:31 | 3 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Sun, 25 Jan 2009

Plone 3 theming for you

So I received lots of useful feedback to my last post. I decided to take a look at collective.skinny again, to try and improve its usability. I really think it's super easy to use now. (Alex, if you still don't think so, let me know why ;-).

So if you're doing Plone skinning in your day job and you haven't taken a look at the package yet, now is a good time to do so. Get a download of the package, include it in your buildout, and hack away. You can also browse the source here. Of particular interest might be the main.pt page template, which is where everything starts.

The PyPI page has details on how to get started with this package, along with a screenshot of the example that's provided as part of it.

Oh, and have I mentioned that this way of skinning works in Plone 3, and there's no reason it shouldn't work with Plone 4, too?

posted at: 19:07 | 13 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Thu, 22 Jan 2009

Plone 3 theming for mortals part 2 -- batteries included this time

So people asked for more details on the supposedly much easier roll your own way of skinning a Plone site in my last post.

I put together an example package called collective.skinny to demonstrate how this could work. You can use this package either as a template to copy and modify, or use it as it is and extend within your own package. Look at the PyPI page for more details.

The package is some 100 lines of Python code with a couple of ZCML statments. As a designer, you'll concentrate on the resources/ and templates/ subdirectories in the package. If you need to extend your browser views with methods, look at base.py and content.py.

To try it out, put collective.skinny in the eggs of your buildout's [instance] part, and add it to the list of zcml includes in the same section. If you look at your Plone site now, you'll see that nothing has changed. To activate the public skin, you'll need to either add a rewrite rule to your proxy as explained in the packages' main configure.zcml file, or activate a subscriber directive that you can find in the same file. This is of course only useful for local development, and even then using a proxy is more ideal, since only then you'll have a way of looking at both the Plone UI and your separate public skin without restarting Zope.

collective.skinny lives in the collective (surprise!). It still has a few rough edges and probably a few bugs. But I'm sure it'll get you started quickly with this easy approach of skinning your Plone site. Let me know what you think of it.

Because Alan mentioned that with this approach your skin will also be much faster, I ran a little benchmark that showed that the standard front page renders about ten times faster than within the Plone skin. Of course the comparison is a bit unfair, since what collective.skinny does is merely get a few attributes from the content object and render them. I don't think that real-world sites have to be much slower than that, though.

Kudos to Sylvain thefunny Viollon for having the idea for the implementation.

Edit: So comments seemed to be temporarily broken on this post. Sorry for that. I really need to switch to Zine. If you have comments and the comments form below doesn't work, please send them to daniel.nouri <at> gmail.com, and I'll put your comment here. I've also made another post describing more improvements to the package.

A few people have already commented:

Alex Limi (who's comment you can actually find below) thinks it's still too hard. Alex, can you tell me what exactly you think is hard?

As to why Deliverance didn't work for us: Since the nature of Deliverance doesn't allow one to add dynamic parts to the site, all the dynamic markup that you can work with is what the Plone UI spews out. That is, if you wanted to display any more data than the Plone default UI gives you (say, a different navigation), you'd have to go back and understand how Plone's UI is put together. Which we decided was too hard for our designer.

David Bain wants some screenshots. Here's one:

/media/skinny.png

Martin Aspeli writes:

I haven't looked at the implementation, but does this not risk "leaking" of the default skin? e.g. what happens if I tack /edit at the end of a URL and you haven't registered an edit view for the context?

Martin, you're right, there's a chance for stuff to leak. I've made some changes to collective.skinny (now: 0.2) so that all pages that the user is not allowed to see will return a 404 instead of the Plone login form. You can still see Plone's UI when you add /view at the end of any URL, though. Some rewriting or reregistering of the main view under those names should help here. I don't think it's a terribly big problem. You don't usually see links to my-content/folder_listing or the like in content.

Michael Mulich writes:

Great job.

This is the best way to make a skin, since it uses the fundamentals of Zope skinning. However, I can't help but notice that collective.skinny does not solve anything for Plone's skinning inefficiencies.

I think this idea would work better if Plone were using zope skinning techniques rather than building off of the CMF's skinning techniques (e.g. SkinsTool). The problem is still that most of the content types people are using are based on ArcheTypes, which is CMF skins based. With zope skinning techniques, which you are using collective.skinny, there is an entry barrier that requires the author to recreate all the content templates, unless ArcheTypes were to take the same approach.

My thoughts on Deliverance are slightly different than most. I love the idea and the ability of Deliverance. However, I believe Deliverance is ignoring Plone's skinning issues. In the end Deliverance is basically candy coating Plone's bitter skinning techniques.

Michael, I think it should be well possible to, in the DefaultView that you can find in the content.py module, fall back to the default view of your content type in Plone (think extracting <div id="content"> from Plone's default HTML). This way one could reuse the standard content view when no specific view for the public skin is available.

I agree with you regarding Deliverance.

Mikko Ohtamaa writes:

Plone 3.0 is very smart piece of software, but it is trapped by its own smartness. It is written by some of the smartest programmers I know, but it they haven't really focused to make things easy for people without the same level of experience.

If we want to make it possible for an average skin jobber to make a Plone skin we need to do it like the other world does out there. This means compromises with the perceived elegancy of the system.

So here is my suggestion.

Let's encapsulate all ZCML, Python, Viewlet, GenericXML, etc. etc. into metacomments of the templates.

You can say:

<html> <!-- @viewlet plone.footer --> <span id="copyright">...

in your template and it will be automatically registered as a footer. No XML or ZCML needed.

TAL has evolved to be a hack ridden piece of unconquerable mountain. nocall: anyone? python:repeat[mymagicvar].end. HTML'ish XML attribute based language may sound good on a paper, but its utterly verbose and rigid nature makes it awful for hand editing. "But we have a Dreamwaver compability!!!1!" Ok, show me a developer who is able to make Plone themes in Dreamwaver.

And for the template language... ask your three friend who work for web design daily what they would want to use. The answer won't please the ear of a hard core software designer, but it is the only right answer if we want to get Plone popularity out of the well of miserably. And it is a decend language if its used as a template language:

I think we should start consider using PHP for Plone templates.

Kamon Ayeva writes:

Hi Daniel,

Have you looked at repoze.bfg.htmlpage (http://pypi.python.org/pypi/repoze.bfg.htmlpage) in the Repoze repository, contributed by Malthe & friends ? From what I understand, it provides an alternative approach to the Deliverance way for a BFG-based site, and it seems similar to what you propose but uses an XSS rules-based technique to handle the way each page part's content is inserted in the main template.

The benefit is that, in their daily work, designers only have to work with the HTML and CSS files that are under a folder similar to /resources (or /html) in the skinning package.

Maybe this is another solution to experiment with for Plone's future skinning story.

Anyway, being also interested by repoze.bfg, I like the idea of repoze.bfg.htmlpage. And it would be great if the community ends up with the best possible compromise that all can benefit from.

Zeitmaschine writes:

@kamon: We've actually implemented something similar for Plone; you can find it at http://svn.plone.org/svn/plone/sandbox/plone.maintemplate/

Sylvain Viollon writes:

I did in October a project using that idea, and Grok skinning technique (with five.grok), and we end up with a really simple and small extension for our skin (even smaller than collective.skinny).

It was porting a Plone 2.1 to 3.0, which was awfully slow.

Building the technique and skin toke us 2 days. We use chameleon templates by default as well, Structured Document for advanced layout / content rendering.

It's blazing fast, and you don't need a super-computer with a ZEO with 8 nodes and an extreme aggressive cache in order to serve a site which actually have quite some traffic, and some data (3.6Go packed, files being stored outside of the Data.fs).

We got as requirement in the project that the loading time of a page should be less than 2 seconds using a regular 8Mb ADSL line, the customer was definitely unhappy with the old response time, and was thinking about changing of technology (i.e. not using Plone anymore).

So if you compare performance and simplicity, I highly prefer to keep things simple and use that instead of Delivrance, and make my customer happy.

http://www.astrium.eads.net/en

posted at: 09:25 | 9 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Mon, 19 Jan 2009

Plone 3 theming for mortals (and web designers who don't want to become programmers)

Plone 3 theming done the conventional way is very painful. There are countless blog posts that tell this story. Catherine Williams' recent post is one of them.

An often overlooked alternative to creating a nice looking site based on Plone is rolling your own, completely separate skin. Once you hook up your own skin, you can forget all about viewlets, ZCML, GenericSetup, and theme away, leveraging your knowledge about HTML, CSS, and ZPT.

In a reply to Catherine's post, I'm explaining the most important aspects of rolling your own theme from scratch, along with some code to get you started. Look for my comment titled Roll your own public-facing skin, it's much easier! :-)

Edit: I made a new post and another one related to this with an extensive example package called collective.skinny.

posted at: 18:31 | 7 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Fri, 19 Dec 2008

Python African Tour: Tutorial in Morocco

Giving a Python tutorial here in Rabat at the Ecole Mohammadia d'Ingenieurs (EMI) turned out to be one of the most amazing experiences I had in a while. Today was the last of two days of Python for about 40 local students in two groups.

The tutorial itself was mostly stealing from Guido's Python tutorial with some modifications and some bits that I added. The clarity and the absence of noise in Python proved to make it very effective for teaching. Thanks to the interactive mode, I was able to demonstrate most concepts on the fly, which works brilliantly.

We used IDLE as the editor, which worked pretty well. Although I didn't have much experience with it, I knew that it would be the most straight-forward to dive in. One thing that I did find annoying about IDLE is that it doesn't print continuation lines (...) in its Python shell. I'm sure it makes it easier to copy and paste text, but it screws badly with indentation, which does trip up a few people.

Some of the students expressed an interest in Python web development. So with only the standard library available and one hour left in the tutorial we tried python -m SimpleHTTPServer, looked at the contents of that module, and at a custom subclass of BaseHTTPServer.BaseHTTPRequestHandler, one that implements a do_GET with a simple way to dispatch URLs.

I sum, I used some 170 slides (with very big fonts), which I'll put online after Morocco. The material turned out to be a tiny bit too much, and thus we skipped some exercises of the last quarter or so. In general, about half of the students were able to finish the examples in time, which gave me lots of confidence. Those who didn't work in pairs were more likely to be in the second half. :-)

I'm still staying in Morocco until Monday, which is way too short. This place is terrific.

Tomorrow we'll see a mini-conference, also at EMI, with some four presentations. Amine Soulaymani talks about Python vs. Java (it seems Java is widely used in schools here also). There'll be a PloneGov presentation, one about OpenERP (Abderrahim El Kafil). The subject will shift away from Python and more to Free Software in general. On Sunday and Monday, there'll be a PloneGov sprint in Casablanca that I'm attending.

Big THANKS go to Kamon and the rest of the Python African Tour team for organizing this, to the wonderful Aida and her hard working colleagues for making everything work out so smoothly here in Rabat, to the rest of the Moroccon students for being super friendly, and last-but-not-least to Joel and the PloneGov team for making this possible!

I think that with the Etape marocaine we've started something great. This is asking to be continued. Hopefully with more couscous, too.

Update: The slides for the Python tutorial are available now.

posted at: 13:59 | 2 comments | category: /devel rss | permanent link | add to del.icio.us or digg it

Mon, 14 Jul 2008

Using Python to wire MIDI into SuperCollider

This weekend, I decided I'd finally make good use of my M-Audio Axiom 25 and wire it up to SuperCollider. What I did to achieve this was write a small Python program that listens to incoming MIDI input and writes OpenSound Control to SuperCollider.

The piece of Python's called midi2sc and it's actually become a somewhat high-level library for assigning MIDI controls to output OSC. It makes use of the excellent pyrtmidi and scosc libraries both developed by Patrick Kidd Stinson.

An example of wiring controls to SuperCollider is provided in the module. Imagine you have a SynthDef defined in SuperCollider that looks like this:

SynthDef("funk", {
  arg freq=700, amp=0.7, gate=1, cutoff=20000, rez=1, lfospeed=0;
  // ...
}).send(s);

Note that this "funk" synth takes 6 arguments, all of which can be controlled while the synth is playing. To control the cutoff frequency with a MIDI control, we define this:

cutoff_control = AbsoluteControl(
    synthdef, min=300, max=7000, param_name='cutoff')

Then, to assign it to a MIDI command, we register a GroupControl to handle commands from a group of continous controllers:

midi = rtmidi.RtMidiIn()
port = ask_for_port(midi)

midi_in = MidiIn(midi, port,
                 handlers={0Xb0: GroupControl({71: cutoff_control})})

The Essentials of the MIDI protocol explains that the 0xb0 MIDI command means we're dealing with a continuous controller, and 71 happens to be the number of the knob that I'm using.

Adding another control is easy. This adds a turning knob for the resonance:

rez_control = AbsoluteControl(synthdef, min=0.10, max=1.5, param_name='rez')
midi_in.handlers[0xb0].controls[91] = rez_control

There's also examples of Note-On, Note-Off, Pitch bend and Channel Pressure controls in the module.

Thanks to the MIDI standard, midi2sc can take input from all kinds of MIDI controllers, including software sequencers like seq24. In fact, I'm having loads of fun with this particular combination; using seq24 to add and remove loops that I prepared and turning knobs on the keyboard to influence the timbre of the notes played.

http://www.filter24.org/seq24/main.png

Sure, there's also MIDI classes in SuperCollider, but I'm still a relative dork in SuperCollider's language sclang. And I like to pretend that this is more compact and readible (and debuggable) than an implementation in sclang.

Update 2009-06-20: I added a GUI and support for configuration files and released midi2sc on PyPI.

midi2sc on the left, together with QjackCtl and Seq24

posted at: 09:35 | 2 comments | category: /devel rss | permanent link | add to del.icio.us or digg it

Sat, 24 May 2008

Arduino: Square wave synthesizer with LFO and variable frequency

After going through part two of this Arduino sound tutorial, I made this little synthesizer.

Click here if you can't see the video.

You can see that it starts out with a constant frequency that can be varied with the potentiometer.

An LFO is added to the frequency once I push the button. Successive button pushes will change the amplitude of the LFO.

While the aforementioned tutorial explains how to connect Arduino with your PC sound card to get sound, I simply plugged in a Piezo buzzer. The advantage being that this synth is totally self-contained and portable, so I could use it in the train (I won't!). The downside is that the audio quality is bad, and it's even worse in the video.

Everything I needed to build this came with the Arduino workshop kit (50 EUR). This includes the Arduino Diecimila itself, potentiometer, buzzer, breadboard, and button.

The button press detection in the Wiring code doesn't work properly. A good implementation would probably need to use interrupt handlers. I ignored this issue for now:

int buttonPin = 7;
int buzzerPin = 8;
int potPin = 2;

void setup() {
  pinMode(buzzerPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

void inner_loop(int j) {
  digitalWrite(buzzerPin, HIGH);
  delayMicroseconds(j*16 + analogRead(potPin));
  digitalWrite(buzzerPin, LOW);
  delayMicroseconds(j*16 + analogRead(potPin));
}

void loop() {
  int val = digitalRead(buttonPin);
  int factor = 0;

  for (int i = 100; i > 0; i--) {
    inner_loop(i * factor);
  }

  // XXX: This doesn't work very well
  if (digitalRead(buttonPin) != val && val == HIGH) {
    factor++;
    if (factor > 3)
      factor = 0;
  }

  for (int i = 0; i < 100; i++) {
    inner_loop(i * factor);
  }
}

posted at: 10:58 | 0 comments | category: /devel/hardware rss | permanent link | add to del.icio.us or digg it

Sun, 18 May 2008

Building an alarm clock

Vanessa and I did some fun experiments lately with Arduino and SuperCollider. We're building an alarm clock that wakes you up with quite an unusual sound...

Read the story here.

posted at: 17:53 | 0 comments | category: /devel/hardware rss | permanent link | add to del.icio.us or digg it

Thu, 08 May 2008

plone.z3cform and why you want to use it (seriously)

I just uploaded a new tutorial to plone.org that explains how to use z3c.form with Plone. z3c.form is the next generation Zope form library and excels through ease of use and very good documentation.

Your feedback is welcome. See also the project's homepage and the discussion on the Plone Product Developers list.

posted at: 15:28 | 0 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Thu, 24 Apr 2008

SuperCollider Help files

I'm now serving the SuperCollider help files. These are available as part of the SuperCollider source distribution (version 3.2) and are licensed under the GPL. Although these files are also available from SourceForge, Google doesn't seem to index them there.

You can search the documentation here:

Loading...

posted at: 17:47 | 0 comments | category: /music rss | permanent link | add to del.icio.us or digg it

Wed, 23 Apr 2008

Debian package download for SuperCollider 3.2

Apparently, SuperCollider is no longer available in the official package repositories for recent versions of Debian and Ubuntu, despite the official SuperCollider download page pointing us there. The lack of a Debian package is quite annoying; besides it can easily bugger a rookie's SuperCollider experience on these systems.

So this is the Debian package that I've built using the infrastructure (namely the debian/ directory) that's already in the source distribution:

Download SuperCollider 3.2 deb package for Debian and Ubuntu

Download the .deb package and run sudo dpkg -i supercollider3.deb to install it! If you have a graphical Debian package installer like the GDebi Package installer, you can use that.

I applied two small patches:

I use Emacs for pretty much everything, that's why the Emacs mode for SC works pretty well for me (although it can be quirky at times...). If you're unfamiliar with Emacs, I suggest you use the fabulous and super easy sced plugin for gedit. The steps for installing sced are a bit cumbersome, but it's totally worth it. Maybe I should try and make a Debian package of sced next.

Update: Ha! A minute after I publish this, I find out that the nice guy behind sced (sorry, I still can't figure out how to write non-ASCII characters here ;-), quite recently released SuperCollider packages for Ubuntu Hardy (which I suppose work for Debian just as well). And his packages look much better than mine. Oh well! :-)

Update: Another update. Our friend behind gedit released a Debian package for gedit. And he's written a short tutorial on how to get started. Go and read it!

posted at: 14:49 | 0 comments | category: /music rss | permanent link | add to del.icio.us or digg it

Wed, 16 Apr 2008

First release of Singing & Dancing

We've been working hard recently. And today I'm pleased to announce the first official release of Singing & Dancing, the next-generation newsletter and notification solution for Plone.

Singing & Dancing Logo by Giuseppe Zizza

Thanks to Thomas Clement Mogensen and all contributors, and kudos to Headnet for their support. And Giuseppe Zizza for making the very cool logo!

Ship it!!

posted at: 11:41 | 0 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Wed, 19 Mar 2008

Singing and Dancing in Sorrento 2008!

If you're still looking for something cool to do at next week's Sorrento sprint besides lying in the sun and sipping on that Limoncello: Why not join us with Singing & Dancing?

posted at: 06:25 | 0 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Thu, 28 Feb 2008

Gnus 5.13 hanging with "Checking mailboxes..."?

I finally fixed my problem with Gnus. I'm writing this, hoping that it'll maybe help someone out there with the same issue.

The symptom: Gnus checks your IMAP mailboxes forever. The problem I had was with one of my mailbox names: I had a ampersand (&) in there, which had Gnus hanging forever trying to escape it. At least that's what looking at *imap-log* suggested. Activating the logging is as simple as executing (setq imap-log t).

The fix: Change your mailbox's name to something without & and update the .newsrc.eld accordingly. And wait for a proper fix. I'm submitting a bug report now.

posted at: 15:20 | 0 comments | category: /linux rss | permanent link | add to del.icio.us or digg it

Tue, 19 Feb 2008

fakezope2eggs

Thanks to fakezope2eggs, I can now in my Zope 2 buildout depend on packages like z3c.form and zc.queue. These would otherwise pull in incompatible versions of packages already in the Zope 2 lib/python directory.

Kudos to Jean-Francois!

Edit: It turns out that the order of the parts in your buildout is very important. Make sure that the fakezope2eggs part comes right after the zope2 part, and before your Zope 2 instance part!

posted at: 14:28 | 0 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Mon, 26 Nov 2007

Don't do this!

This project is frustrating the hell out of me.

If you want to customize your Plone site, don't do this:

  • Go around wildly in your Products folder in customization frenzy and patch files like there's no tomorrow; and not even write down what you changed where. Monkey patches are a hundred times better than this!
  • Make customizations in the ZODB that your filesystem code depends on, so that you can't use the filesystem code anymore without that exact same database. Have fun reproducing your environment!

Please, these things are totally disastrous. You might just as well throw your Plone site out the window!

Gaah!!

(Thanks to Florian Schulze for being an inspiration to the title for this blog post.)

posted at: 11:21 | 4 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Thu, 18 Oct 2007

Timed caching decorator with plone.memoize

Will McGugan recently blogged about his timed caching decorator. And today I found out about gocept.cache, which allows you to memoize a function for a given amount of seconds.

This is how you would cache a function's value for an hour using plone.memoize:

>>> from time import time
>>> from plone.memoize import ram
>>> @ram.cache(lambda *args: time() // (60 * 60))
... def fun():
...     return "Something that takes awfully long"

In the same way we're making the cache depend on time here, we could have it depend on anything else, like certain arguments provided to the function. So, really, we can do more than just memoization with plone.memoize; an example is this time-out application.

See the plone.memoize docs for more examples.

posted at: 07:35 | 1 comments | category: /devel rss | permanent link | add to del.icio.us or digg it

Sun, 30 Sep 2007

SuperCollider Symposium 2007

I attended the SuperCollider Symposium 2007 in The Hague last week, which was fantastic. So many interesting people with their interesting projects gathered in one place! Too bad I missed out the last part of the symposium because of a cold.

Dan Stowell blogged about the symposium. There's some other cool things to discover on his page, like his Evolutionary Sound System (which he developed with SuperCollider), and him getting his hair cut.

Gregorio Garcia Karman took some nice photos at the conference.

You can learn more about SuperCollider on the SC home page and on Wikipedia. You might find these links particularly useful:

posted at: 09:01 | 0 comments | category: /music rss | permanent link | add to del.icio.us or digg it

infrae.subversion: a recipe against disaster

After finding out about plone.recipe.bundlecheckout yesterday, I thought I'd mention infrae.subversion, a similar recipe for zc.buildout. These are the key differences:

  • p.r.bundlecheckout allows you to specify one URL per part, whereas with infrae.subversion you can specify a list of URLs. Why does this matter? Because it helps you keep the exact URLs and therefore versions of the components that you use in your buildout configuration, which is better than keeping them in a svn:externals property.

  • infrae.subversion takes care not to wipe any changes that you might have done in the checkout. That is, you can safely use its checkouts for development.

    Why not instead make a separate products directory and use svn:externals for development? Because again, we want to keep all dependencies in the buildout configuration. And it's good to keep the development buildout as close as possible to the deployment one, to minimize the chance of error. With infrae.subversion, you also have the advantage of being able to run bin/buildout and have all dependencies updated, instead of having to run svn up in some directory manually, which is a source of confusion.

  • p.r.bundlecheckout works with both SVN and CVS, while infrae.subversion only works with SVN.

The Silva buildout is an example of a buildout that uses infrae.subversion.

plone.recipe.command

This is another buildout recipe that I should quickly mention. It can be used to run arbitrary shell commands at install or update time. Here is an example that uses the beforementioned infrae.subversion recipe to install the latest Plone's FCKeditor Product from SVN. The reason for using plone.recipe.command here is that we need to call the base2zope.py script to bootstrap the Product after doing a checkout:

[my-products]
recipe = infrae.subversion
urls =
  https://svn.plone.org/svn/collective/FCKeditor/trunk FCKeditor
  ...

[prep-fckeditor]
recipe = plone.recipe.command
command =
    ${buildout:executable} ${buildout:directory}/parts/my-products/FCKeditor/utils/base2zope.py
update-command = ${prep-fckeditor:command}

You can find more buildout recipes in PyPI.

posted at: 08:58 | 1 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Sat, 09 Jun 2007

Need for speed? Go plone.memoize

If you need to speed up your Python application, you should take a look at plone.memoize, in particular its new cache decorator that's really easy to use:

>>> from plone.memoize.ram import cache
>>> def cache_key(fun, first, second):
...     return (first, second)
>>> @cache(cache_key)
... def pow(first, second):
...     print 'Someone or something called me'
...     return first ** second

>>> pow(3, 2)
Someone or something called me
9
>>> pow(3, 2)
9
>>> pow(3, 3)
Somone or something called me
27

You can see that the cache key function determines which input values result in the same output and thus can be cached. Cache key functions receive exactly the same arguments as the functions that they cache, plus the function itself. Thus, key functions for methods can also use self for determining a cache key. A cache key function may raise the DontCache exception to signal that no caching should take place.

The cache storage backend can be freely chosen using the second argument to the cache decorator:

>>> @cache(cache_key, cache_storage)

where cache_storage is a function that again takes all arguments of the original function and returns a dict-like object for use as a cache storage. plone.memoize has built-in support for memcached and zope.app.cache as storages.

See the doctests for volatile.py for more examples.

For now, you'll need to use the SVN version. A release containing the cache decorator will follow soon.

posted at: 15:10 | 0 comments | category: /devel rss | permanent link | add to del.icio.us or digg it

PIKtipi sprint

Tom thought it'd be a good idea to write down what we were up to at the PIKtipi sprint (2nd to 7th of June), so here's my wrap-up:

PIKtipi was my third Plone sprint so far in 2007. I had an excellent, and productive time, thanks to all organizers. Here's what I did:

  • Develop further plone.memoize and make use of it in the portlets implementation of Plone 3. Together with Hanno, we were able to speed up Plone for anonymous users by about 50%, and for logged in users by about a third. Stefan helped me implement the memcached support.
  • Fix some bugs for the 3.0 release of Plone. By the way, if you're one of the 145 Plone providers earning money with Plone, you should consider helping out. Plone 3 will have loads of new features, but that also means that the bugtracker needs increased attention to get all these features stable.
  • Have a fun time with fellow Plone developers, and attend the DZUG conference that was running in parallel.
  • In Berlin, run into a 3 hour DJ set by Ellen Allien by accident. Thanks to Siebo and Saskia for their great company. :-)

posted at: 07:48 | 0 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Tue, 29 May 2007

Samsung YP-U2

My iPod shuffle recently broke completely, a couple of days after the warranty had expired. I'm a bit angry I had to trash it so early. Apparently, I'm not the only one having trouble with the iPod shuffle. Also, while trying to get support for my problem I've found that Apple's customer service sucks.

So, I needed to replace the iPod with something else. I noticed that they were dumping the same shuffle model that I had (first generation) at the electronics store for 30 EUR. I resisted, and went for the somewhat similar Samsung YP-U2 for 70 EUR.

http://samsung.com/Products/MP3Player/MP3Player/images/b2c_l_ypu2blk.jpg

And the Samsung is really nice so far:

  • it has a display with very useful configuration options, unlike the shuffle,
  • it has a nice equalizer with many presets, unlike the shuffle,
  • it's a USB mass storage device that lets you drop your music right in, unlike the shuffle, which requires you to jump through hoops to have transfer of music working without using iTunes,
  • it's got USB that you can directly plug in, no need for an adapter, like with the shuffle,
  • it supports Ogg Vorbis, unlike the shuffle. Although I've kinda given up on Vorbis quite a while ago after realizing that my MP3 player back then wouldn't support it, it's nice to see that Samsung apparently cares and supports this free format.

posted at: 23:15 | 1 comments | category: /music rss | permanent link | add to del.icio.us or digg it

Sun, 27 May 2007

Patterns, simplicity and simple patterns

Five Easy Pieces - Simple Python Non-Patterns from Alex Martelli was something that I had tagged toread for quite a while now, and it turned out to be a very interesting read.

The most important point that Martelli makes in this paper is that in Python, some of the traditional software design patterns don't apply, because the Python programmer has facilities that other OO languages lack, the lack of which makes certain patterns necessary in other languages that seem superfluous in Python.

It's nice how Martelli puts context into this topic, by explaining some of the background of patterns. Most notably, he references a book called A Pattern Language - Towns, Buildings, Construction by Christopher Alexander and a paper called The Structure of Pattern Languages by Nikos Salingaros, which is available online.

There's quite a nice analogy between software patterns and architectural design patterns. The dictionary of design patterns of Christopher Alexander lists examples for patterns found in architecture like SMALL PARKING LOTS, for which the summarizing statement is Vast parking lots wreck the land for people.

Interestingly, both Alexander and Salingaros are harsh critics of modern architecture. Salingaros writes:

Architecture has changed in this century from being a trade serving humanity with comfortable and useful structures, to an art that serves primarily as a vehicle for self-expression for the architect. In the current architectural paradigm, the emotional and physical comfort of the user are of only minor importance.

Well, this reminds me of software architects who care more about their design than users. The Big Design Up Front page in the PPR has some nice quotes and statements that go with this.

It makes sense to me when Martelli explains how some patterns are unnecessary in Python and others that tend to be involved in other languages are very easy in Python. Need a Singleton? Just create an instance of a class and have clients access that instance by its name. Need a registry? Make a module global instance of a list or dict, and have append and remove be your register and unregister functions. In Eby's article Python is not Java, one reads about a software project:

So, the sad thing is that these poor folks [a team of former Java developers who were new to Python] worked much, much harder than they needed to, in order to produce much more code than they needed to write, that then performs much more slowly than the equivalent idiomatic Python would.

Simplicity is the key to quality, and simple definitely beats complex. Test-first is probably a good way to create simple designs. The KISS principle represents:

If you have a choice between a simple solution and a complex one, then opting for complexity would be stupid.

And:

All design should be as simple as possible, but no simpler. [...] the more elegant designs are usually the more simple ones. Simple also does not mean quick and dirty. In fact, it often takes a lot of thought and work over multiple iterations to simplify.

Python code is by nature simpler than code in many other languages, because it lets you focus on your actual problem -- making simplicity a built-in feature, and apparent that the source code is the design. Finally, a nice quote from Kent Beck found in the PPR:

As a consultant, 80% of the time my job involves taking out premature abstraction so we can get the damned thing out the door.

For me, the PPR is an enormous repository of insightful ideas about software development. I've already emptied my cup and I'm surfing for my next zen slap! :-)

posted at: 07:37 | 2 comments | category: /devel rss | permanent link | add to del.icio.us or digg it

Sat, 26 May 2007

eXtremeManagement tool is getting there

If you've tried the eXtremeManagement tool (or: XM) before, you may have noticed that it's not exactly an interaction design masterpiece. Doing a simple thing like booking your hours for the last week easily took you a few dozen clicks, and that with a web application that takes its time to respond. Getting an overview over your iteration (XM's loosely based on Extreme Programming ideas) used to be hard too. Because of the hierarchical way XM lays out iterations, getting from an project overview to a task that you were interested in would easily involve three clicks. And that's for getting an overview. What if you forgot the details about the task when you were back on the overview page? Considering that a project easily spans half a dozen stories per iteration, this was an overview nightmare.

At Jazkarta, we've been thinking a lot about what the right project management tool would be for us. We were fed up with XM and its sluggishness -- one project tried out Trac combined with some booking plug-in, but it turned out that Trac lacked the project management view of things, or that we were unable to produce the right reports, something that the eXtremeManagement tool is considered to do well out of the box. We looked at other projects and services on the web, but it looked like XM, despite being sluggish, was still the best thing there was. (If I had my way, we'd try to strip XP to the bones first, not thinking about existing tools, and try to understand the process more before we try to modify it.)

So, we looked at improving the tool. XM's trunk now features a simple expand button in the iteration view that lets you drill down to tasks. That is, when you're looking at the listing of stories, you can click an arrow to see the list of associated tasks inline, without any loading time. Malthe, a fellow from Jazkarta, thinks it's cool:

<malthe>  Oh my god! What happened to XM?
<malthe>  It's a UI revolution!
Toggle story before Toggle story after

Another missing link in XM used to be the tracker integration. When your task was about fixing a bug in the tracker, your XM task would have no notion of the Poi issue that you were fixing (-- Poi is the bugtracker that we use). Consequently, you had to manually take care of linking the one with the other in the respective text fields, and that, of course, is more than dull, and it breaks easily (think moving around tasks in the system) and not doing it meant no good overview of things.

Now, the way I like to work with XM and Poi is that almost everything everything that I do goes into an issue. Because Poi has much better facilities for maintaining a dialogue with the customer, and Poi issues can have a longer lifetime than tasks -- they can be relevant for more than one iteration. (With stories and tasks that are bound to an iteration in XM's model, that's a bit hairy.)

With the new Poi Task on trunk, connecting tasks with issues finally makes sense. A Poi Task can be connected to one or more issues. The view of the Poi Task will show you all the issues that are associated with it, together with their status (unconfirmed, open, closed, etc.). On the other side, an issue will show you the tasks it's associated with. Plus, you now have a one-click way of adding a task for our issue to any open story in your project.

Poi integration for XM

Also, Poi trunk now has auto-linking to other issues and Trac. Like in Trac itself, you can now simply write #123 in your report and get a link to that issue. The same goes for r123 and revisions in Trac.

The next thing my TODO for the XM tool is gtimelog integration. I want to be able to retrieve a task list from a XM project, and book my hours directly from gtimelog. This is by the way how the folks at Infrae have been booking their hours for a while now into their in-house timesheet app. This integration will mean that I'll no longer need to write down my hours into three different places by hand.

gtimelog

So... If you're looking for a project management tool that's flexible and XP, or if you've looked at XM before and you thought it's dull or doesn't give you enough overview, try it (again). I think it's grown to quite a usable solution for project management. By the way, thanks to Zest and Jazkarta for supporting this work.

posted at: 07:50 | 4 comments | category: /devel rss | permanent link | add to del.icio.us or digg it

Sun, 20 May 2007

Monkey business

Two weeks ago, I went to Apenheul, which is not your typical zoo: In Apenheul, apes and monkeys walk around freely. Apparently, the Rotterdam Zoo is trying out the same concept lately, with a Gorilla hanging out in the zoo's restaurant.

posted at: 07:43 | 0 comments | category: /misc rss | permanent link | add to del.icio.us or digg it

Fri, 23 Mar 2007

*Isolated* doctests for Plone

For those of you who say they don't like doctests because they don't give you isolation between tests. Here's an example of an integration doctest for Plone that gives you exactly that:

from Testing import ZopeTestCase as ztc
from Products.PloneTestCase import PloneTestCase as ptc
from Products.PloneTestCase.layer import PloneSite

ZOPE_DEPS = ['MyZopeProductDependecy']
PLONE_DEPS = ['MyPloneProduct',
              'MyPloneDependency']

for x in ZOPE_DEPS + PLONE_DEPS:
    ztc.installProduct(x)
ptc.setupPloneSite(products=PLONE_DEPS)

class MyTest:
    def test_one():
        r"""
        Check if one and one is two:

          >>> 1 + 1
          2
        """

    def test_two():
        r"""
        Check if one minus one is zero:

          >>> 1 - 1
          0
        """

def test_suite():
    suite = ztc.ZopeDocTestSuite(test_class=ptc.PloneTestCase)
    suite.layer = PloneSite
    return suite

Look at G. Writing Tests in the (somewhat out of date) The Zope 3 Developer's Book for more inspiration.

Don't do traditional-style unit tests, they're ugly. Is this a matter of test, err taste? I don't think so.

Of course, if you want real isolation, you go for unit tests (i.e. no ZopeTestCase involved). People are usually scared and say, but then I need to set so much up by hand, or, don't make me write a mock object for everything, but those arguments aren't really valid most of the time. This is how easy a pure unit test using doctest for a Plone Product (or any Python program) can look like:

import unittest
from zope.testing import doctest

class Add:
    r"""
    >>> 1 + 1
    2
    """

class Subtract:
    r"""
    >>> 1 - 1
    0
    """

def test_suite():
    return unittest.TestSuite((doctest.DocTestSuite()))

If you have a hard time creating mock objects to test against, try Mocky. This is an example of mocking a CMF site that gives you getPhysicalPath, has a portal_catalog and some special site_properties for use with your content type:

>>> from mocky import Mocky
>>> import Acquisition
>>> class MockySite(Mocky, Acquisition.Explicit):
...     def getPhysicalPath(self):
...         return tuple(self.name.split('.'))
...     def portal_catalog(self, **kwargs):
...         return []
>>> site = MockySite('site')
>>> props = site.portal_properties.site_properties
>>> props.getProperty = lambda x: 'utf-8' # doctest: +ELLIPSIS
Set site.portal_properties.site_properties.getProperty to <function ...>

>>> from Products.MyProduct.content import MyContentType
>>> content = MyContentType('someid').__of__(site)
>>> content.something_that_involves_using_portalcatalog_and_siteproperties()
'your result here'

Update: The python-in-testing list has an interesting discussion about doctest vs. unittest.

posted at: 10:06 | 0 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Sat, 10 Mar 2007

Invaluable Zope 2 development tools

I never leave home without these, at least not when I leave home to do development:

  • Emacs

    Emacs of course isn't specific to Zope or Python. Nevertheless, Emacs is the editor for doing Zope development. Check out Philipp von Weitershausen demo pdbtrack. You need nothing more than the usual python-mode for this. (If you don't know what pdb is, read this gentle intro to debugging in Python.)

    I hear that other editors can do this too, but it can't possibly work as well. :-P

    Start with Emacs basics right now!

  • Firebug

    You've certainly been living under a rock if you haven't heard of Firebug before. Never was trying out and debugging JavaScript so joyful. Firebug has an interactive JavaScript shell that since version 1.0 also has access to the variables in the scope of any breakpoint that you might have set.

  • PDBDebugMode

    What it does: It loads the Python Debugger (pdb) whenever Zope encounters an exception that was not filtered in the error_log. In combination with pdbtrack this means: Don't read tracebacks to find out where the exception has occurred and where you might want to hook in to debug. And don't restart after you figured out where to put that pdb.set_trace(). Instead: Have your pdb point to the failing line of code and do your debugging right away. Works similar to --debug-inplace of the Zope testrunner.

    This might be not as useful for development of new applications (think tests) as for situations where you have to debug something quickly, possibly on a live deployment.

  • ScriptDebugging

    Before, I totally hated debugging code in Script (Python) objects. That was until I found Lennart Regebro's ScriptDebugging, which helps pdbtrack find out where in the script you are, which means that you can debug scripts just like any other Python code.

  • DeadlockDebugger

    Stuck with a Zope that's stuck? If your Zope stops responding, use DeadlockDebugger to find out where exactly Zope's threads are deadlocked. From the author:

    This product adds a hook so that a deadlocked Zope process can be debugged, by dumping a traceback of all running python processes. The dump is sent to the event log (at the DEBUG level) and returned to the browser (even though the Zope is deadlocked and doesn't answer any other requests!).

    DeadlockDebugger can of course also be used to debug Zope in non-deadlock situations, when a Zope process is taking a long time and you wish to know what code is being executed.

What's the Zope 2 tool that you'd take with you on an island?

posted at: 12:34 | 3 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Thu, 01 Mar 2007

Luke Slater party in Second Life

Luke Slater's party on Second Life is starting now in the Alpha Box. He'll be playing his DJ set in less than an hour!

/media/luke-slater-sl.jpg

posted at: 15:03 | 1 comments | category: /music rss | permanent link | add to del.icio.us or digg it

Wed, 28 Feb 2007

FOSDEM 2007

Last weekend, I went to my first FOSDEM (video recordings). I took my girlfriend with me, which I believe helped her understand my nerdy side better. ;-)

Paul Everitt did a nice presentation on Plone 3, where he showed how you set up a Plone 3 instance using ploneenv, and then an easy example of using KSS, and some other Plone 3 niceties. The ploneenv screencast is available now, and so is the rest of the screencasts that Paul demos at the presentation.

Paul was followed by Dries Buytaert's Drupal presentation, which was also really good. It was more a demo of what Drupal is and what it can do for the end user, as opposed to how you can develop for the platform and some legal background, which Paul concentrated on.

Unfortunately, I missed the OLPC talk, but nevertheless I was able to get my hands on one of those laptops, and they really do look cool.

Elixir, a library built on top of SQLAlchemy that's recently gone into beta, looks like a very convenient way to talk to relational databases.

Amazing how a conference with so many good talks can be totally free. Next FOSDEM? I'll be there...

Update: Added a link to the ploneenv screencast.

posted at: 14:34 | 0 comments | category: /devel rss | permanent link | add to del.icio.us or digg it


< March 2009
SuMoTuWeThFrSa
1 2 3 4 5 6 7
8 91011121314
15161718192021
22232425262728
293031    

Feed of all categories: rss rss | atom

Categories: