Daniel Nouri's Old Blog

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

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: 16:31 | 3 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Mon, 26 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: 02: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: 16:25 | 9 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Tue, 20 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: 01:31 | 7 comments | category: /devel/zope 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: 22:28 | 0 comments | category: /devel/zope 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: 18: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: 12:25 | 0 comments | category: /devel/zope 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: 21: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: 18:21 | 4 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Sun, 30 Sep 2007

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: 15:58 | 1 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Sat, 09 Jun 2007

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: 14:48 | 0 comments | category: /devel/zope 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: 16: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: 19:34 | 3 comments | category: /devel/zope rss | permanent link | add to del.icio.us or digg it

Mon, 26 Feb 2007

Baarn Sprint 2007

/media/baarn-2007.jpg

This year's Baarn sprint was way cool! And we got a lot of stuff done.

I really like the multi-cultural aspect to Plone sprints. Where else do you get to meet and work face to face with people from Norway, the Netherlands, Scotland, Great Britain, Germany, United States, Hungary, Belgium, Finland and Austria in the course of a couple of days?

Seeing some people that I've never met in real life before was very nice, too. That'll help with communicating with those people through IRC and mailing lists.

Thanks everyone for a fantastic time! I'm totally looking forward to the Sorrento sprint, where over 60 people are expected!

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

Fri, 16 Feb 2007

ploneenv recipes

I've updated the experimental Plone 3.0 setuptools distribution and ploneenv today a bit and fixed some bugs along the way.

Here are some small recipes that show you how ploneenv works, and how you can make use of it.

A requirement for all of these recipes is that you have ploneenv installed, which you can install like this:

sudo easy_install ploneenv

The recipes will also assume that you have two shell variables set. One is MKZO, the path to the mkzopeinstance.py script of your Zope 2.10 installation. The other is INSTANCE_HOME, the folder where you want your Zope instance to go into. This is an example of setting those variables:

MKZO=~/lib/Zope-2.10/bin/mkzopeinstance.py
INSTANCE_HOME=~/myplone3.0

Create a pristine Zope instance

Goal

You want to create a pure Zope instance, in which you can use tools like easy_install and yolk to manage Python packages and install Products the usual way.

Recipe

Use this command:

ploneenv $INSTANCE_HOME -m $MKZO --no-requirements
What this does

Calling ploneenv with --no-requirements will create a blank Zope instance that's also a workingenv. This method of installation is perfectly compatible with Plone 2.5 or other Products!

To install packages from the Cheese Shop, you must first activate the environment and then use easy_install, like this:

source $INSTANCE_HOME/bin/activate
easy_install yolk

This will install yolk, a tool that provides a lot of useful functions for querying the metadata of installed setuptools packages and querying the Cheese Shop. For example, if you want a list of all packages that are installed in your Zope instance, run:

yolk -l

Create an instance with Plone 3 from Subversion in it

Goal

You want to try out Plone's latest development version straight from Subversion.

Recipe

Follow the steps from Create a pristine Zope instance and then, after having activated the instance's environment via source $INSTANCE_HOME/bin/activate, do:

easy_install Plone==dev
What this does

This will download and install Plone's current development version. This way you can experience the latest and greatest (and potentially most unstable) Plone.

Create an instance with a Plone 3 release in it

Goal

You want to create a Zope instance with the latest Plone 3 release in it.

Recipe

Use this command:

ploneenv $INSTANCE_HOME -m $MKZO
What this does

This will install the latest Plone version from the Cheese Shop. Right now this is 3.0-r12165, an experimental and arbitrary snapshot of Plone 3 dating back to the 4th of February. Note that it's not related to the real Plone 3.0a2 release, which is the latest official release of Plone 3 and what you normally want to use.

Develop packages for Plone 3

Goal

You want to develop a package for Plone 3.0. We'll call this package mypackage.

Recipe

Follow the steps in Create an instance with Plone 3 from Subversion in it.

Install ZopeSkel and create your package if you haven't one already:

easy_install ZopeSkel
paster create -t plone mypackage

Activate your instance's environment if you haven't yet and install your package in development mode:

source $INSTANCE_HOME/bin/activate
cd mypackage
python setup.py develop
What this does

You are encouraged to create your new Plone 3 modules outside of the Products directory/package. ZopeSkel helps you with quickly setting up a distribution.

Invoking python setup.py develop inside of your newly created project will install your package in development mode.

There are good reasons to still use Products. When you develop a Product, just link it into your instance's Products directory as usual.

Note that you can override Products or packages that come with Plone this way, which enables you to develop parts of Plone itself.

Status quo

Plone 3.0, ploneenv and the Plone egg distribution are under heavy development still. Therefore you might encounter errors while trying out these recipes. Please report those!

There is one known problem with ploneenv, where easy_install attempts to compile Script (Python) files and spews a lot of error messages. However, those error messages are not critical, and the installation succeeds nevertheless.

If you're developing Plone 3 itself, you might want to go for ploneout, which is the mechanism used by most Plone developers who actively develop Plone.

My previous blog on ploneenv has some more pointers and info.

Update: Thanks to Paul Everitt, there is now a ploneenv screencast.

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

Sat, 03 Feb 2007

ploneenv, or YAWTSUYP (yet another way to set up your Plone)

What is ploneenv?

ploneenv builds a Zope instance that is also a workingenv and installs (by default) Plone 3.0 in it.

There are other packages out there that can do the same:

The most prominent of these packages is ploneout, a Zope Buildout configuration (including add-ons) that allows you to install Zope and Plone 3.0 in one step. While this is a very appealing solution in most situations, sometimes it is more comfortable for a developer to work more interactively, in an environment where packages can be installed and tested out, removed, replaced and queried using the standard easy_install and tools like Yolk.

So what is ploneenv? ploneenv is a one module Python script that builds heavily on workingenv and setuptools. What it does:

  • It creates a Zope instance for you. You always provide the mkzopeinstance.py script that you want to use as an argument. E.g.:

    ploneenv ~/myzopeinstance --mkzo=~/lib/Zope-2.10/bin/mkzopeinstance.py
    
  • It creates a workingenv in the Zope instance for you.

  • It installs the Plone egg by default. However, you could just as well install something else in your new Zope instance using the --requirements argument. ploneenv is not Plone specific.

These steps are quite similiar to what you do manually when you make your Zope instance a workingenv.

Give me some examples

This is how you use ploneenv to install Plone:

easy_install ploneenv

MKZO=~/lib/Zope-2.10/bin/mkzopeinstance.py
INSTANCE_HOME=$HOME/myplone30

ploneenv $INSTANCE_HOME -m $MKZO

At this point, you can install any extra packages. This would install simplegeneric:

source $INSTANCE_HOME/bin/activate
easy_install simplegeneric

Old-style Products that aren't wrapped in eggs are installed as usual:

cd $INSTANCE_HOME/Products
wget http://plone.org/products/ploneformgen/releases/1.0.3/ploneformgen_1-0-3.tgz
tar xzfv ploneformgen_1-0-3.tgz

You can also override Products that come with Plone. For example, you could set a symlink from your local CMFPlone checkout into the $INSTANCE_HOME/Products directory and hack away.

To use a local SVN checkout to develop an existing or new new-style Plone package, you would simply do:

cd ~/myproject
python setup.py develop

Note that except for the activation of the environment, this is exactly how you would install a package for development in Python (=setuptools). That is, this is not ploneenv nor workingenv specific.

Try it out!

Please try it out and give me feedback. As mentioned before, this is all you need to type:

easy_install ploneenv

MKZO=~/lib/Zope-2.10/bin/mkzopeinstance.py
INSTANCE_HOME=$HOME/myplone30

ploneenv $INSTANCE_HOME -m $MKZO

That's it! Just make sure that you set the MKZO and INSTANCE_HOME according to where your mkzopeinstance.py script is and where you want to create your instance respectively.

Now you can start Zope using $INSTANCE_HOME/bin/zopectl fg.

What's inside the Plone egg and why

The Plone egg goes back to some early experiments I did to package Plone. Plone is a meta-package that has a Products namespace and currently all old-style Products that Plone requires contained in it. On top of that, it defines a number of requirements, like elementtree and plone.openid.

By not mixing installation code with the package itself, the Plone egg makes sure that it can be installed in any context, for example in a ploneout.

If the CMF were to became available as an egg, Plone would remove it from its own contents and just define another requirement.

The tagged and released Plone egg (or bundle, if you like) should arguably not have svn externals that point to other Products' SVN trunks. Instead it should either use svn externals to SVN tags of Products where possible or include the Product itself if it's not maintained in subversion. This might seem a bit hacky, and Rocky says I'm cheating, but it effectively brings the Plone package more inline with other Python packages out there, with all the benefits that this brings. IMO, this should be the way to release Plone 3.0.

Discussion happens on the Plone development list.

Update: I've updated this entry to reflect the fact that ploneenv and Plone are now in the Cheeseshop, so the installation becomes a lot easier.

Update: I've retired ploneenv in favour of repoze (especially repoze.plone). repoze is what ploneenv wanted to be, and more.

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

Tue, 30 Jan 2007

New Zope 3 and GenericSetup intro tutorial on plone.org

Check out this new tutorial that helps you get started quickly with Product development in Plone 2.5 and higher. Why another tutorial? Because I myself needed a simple resource where I could copy and paste the most important snippets from. And because Plone needs more easy and practical get-started tutorials.

Thanks to Infrae and Wim who helped me write it!

Ideas I have to extend this tutorial:

  • How to convert the Product into a ZopeSkel template
  • How to use a formlib form for the search page

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

Sat, 27 Jan 2007

LovelySync in Collective

LovelySync is a small and quite flexible library for importing data into the ZODB, the object database that Plone uses. In theory it can be used as a library for anything that needs to be imported into any database (yeah, sure I hear you say). But I've only ever used it with the ZODB as the target database.

One of Lovely's customers needed to synchronize a Filemaker database regularly with their Plone site. The database was quite complex; it had different languages (which we mapped into LinguaPlone content), images, and all kinds of references between the objects. At the time I began working for the project, we didn't know exactly how the export format would look like, so we had to develop something that was easily adjustable: The input format is easily customized using schema files. All the actual writing is delegated to small specialized components called WriteHandlers. Reading is done by the Reader, which supplies the Writer (which is the object delegating to WriteHandlers) with Records. You might want to check out the interfaces file for the technical details.

LovelySync, originally written more than a year ago, but refactored a lot lately, was the first project where I used the Component Architecture of Zope 3 extensively, and quite successfully (and without ZCML ;). Using LovelySync, I've been doing imports for hundreds of members from a CSV file into Plone, screen scraping contents into Plone sites for migration, and even an import of usenet (NNTP) groups into Listen through nntp2listen, which will be in a public SVN shortly.

So if ArcheCSV doesn't exactly do what you want, and PLIP 112 is too far away for you, you might want to try LovelySync.

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

Wed, 24 Jan 2007

PDBDebugMode Product

What a nice Zope Product I found today. Ross Patterson's PDBDebugMode allows you to:

  • post-mortem debug any Zope exceptions while Zope is running in foreground,
  • debug traversal when you provide the special query parameter pdb_runcall in the URL and
  • import pdb in restricted code.

The README has more details.

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

Fri, 29 Sep 2006

Framework shootout

Of cardinals and ambassadors

It's now almost one month that I work for Infrae, and I enjoy it a lot. I have a nice working environment with friendly colleagues and interesting projects. And I get to share my workplace with Martijn Faassen, which rocks, because I can learn so much from this guy!

The other day I went to the COM.lounge TV page to check out Martijn's keynote at this month's DZUG conference. It was fun to watch. And then I discovered four other very interesting videos from this year's Europython conference in Geneva. I wasn't there, so I was eager to see the recording of the Web framework shootout which took place there. I was particularly impressed about Kevin Dangoor's presentation of TurboGears. If this is not the incarnation of agile development, then I don't know what! Kevin upstaged the other two contestants Simon Willison (representing Django) and Philipp von Weitershausen (of Zope 3).

Drawing the bow back to Martijn's presentation, I totally agree with him that Zope 3 needs another face on the web. Finally, he and some others are doing something about this. They're still looking for help from you!

Also, the eggification of Zope 3 packages, which is landing slowly, will help in making Zope 3 popular in the wider Python community.

Zope 3 = Ninja Power?

But Zope 3 has also another problem IMO: It's hard to grasp. Even if it's less confusing than the huge inheritance trees in Zope 2, Zope 3 has still to go a long way to be as newbie-friendly as, say, TurboGears. Again, Martijn comes to the resuce: In October he'll be sprinting with the people from Gocept with the goal to flatten Zope 3's learning curve. The project is called Grok, and it sounds really promising.

Honestly, I think that if I hadn't known the concepts of Zope 3 before, I wouldn't have understood much of what Philipp explained at the shootout. I don't buy the it's complex because it solves complex problems argument. Python is a good example of a very approachable technology that can scale sky high.

When following the mailing lists of TurboGears, I noticed that their team considers lack of documentation, especially in the form of approachable tutorials, a bug. Now, Zope 3 comes with lots of doctests, which I find great. But they're not exactly approachable for newbies. Not because of their style of writing, but because they are in places where newbies don't look, i.e. in the source tree.

Benji York created the very nice Zope 3 Quick Start Guide, which I personally recommend to anyone who starts with Zope 3. Also, zeapartners.org has two nice little screencasts. We definitely need more tutorials like this! And fewer Zope 3 packages with the hidden ninja wisdom feel to them.

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

Fri, 16 Jun 2006

pluggablecatalog

I added a new project called pluggablecatalog to the collective.

pluggablecatalog is a replacement (or rather: a wrapper) for Plone's portal catalog. It adds the ability to plug in default search restrictions without the need to subclass or monkey- patch the catalog.

From the docstring of pluggablecatalog/tool.py:

Wraps CMFPlone's CatalogTool to add default parameters
collected from IQueryDefaults utilities.

  >>> from Products.pluggablecatalog.tool import CatalogTool
  >>> catalog = self.portal.portal_catalog
  >>> isinstance(catalog, CatalogTool)
  True

We create two documents and make sure they're indexed:

  >>> len(catalog())
  0
  >>> self.folder.invokeFactory('Document', 'doc1')
  'doc1'
  >>> self.folder.invokeFactory('Document', 'doc2')
  'doc2'
  >>> doc1, doc2 = self.folder.doc1, self.folder.doc2
  >>> doc1.setTitle('First Document')
  >>> doc2.setTitle('Second Document')
  >>> doc1.reindexObject(); doc2.reindexObject()
  >>> len(catalog())
  2

Let's now add a rather stupid IQueryDefaults utility that
restricts searches by default to objects with the Title 'First
Document':

  >>> from zope import component
  >>> from zope import interface
  >>> from Products.pluggablecatalog.interfaces import IQueryDefaults
  >>> def myDefaults(context, request):
  ...     return {'Title': 'First Document'}
  >>> interface.directlyProvides(myDefaults, IQueryDefaults)
  >>> component.getService('Utilities').provideUtility(
  ...     IQueryDefaults, myDefaults)

With this utility in place, we should only retrieve doc1 now,
unless we explicitly provide a 'Title' query parameter:

  >>> len(catalog())
  1
  >>> catalog()[0].getObject().aq_base is doc1.aq_base
  True

  >>> len(catalog(Title='Second Document'))
  1
  >>> (catalog(Title='Second Document')[0].getObject().aq_base is
  ...  doc2.aq_base)
  True

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

Sun, 11 Jun 2006

Record and test Plone with zope.testrecorder and zope.testbrowser

I've just updated the HOWTO for using Testbrowser and Testrecorder with Plone. The Testbrowser/Testrecorder combination is so easy; also for non-programmers. We need more structured and well-documented functional tests like this, because they make our lives easier [*]. Maybe you can help out?

[*]... and our tests slower? ;-)

And Now for Something Completely Different

While I played around with Testrecorder, I wrote a small script for text match and replace using regular expressions. This is arguably one of the most unreadable pieces of code I've written in a while. But to the rescue come the doctests, which I've used to develop this test-first.

I don't know anything about Ron Jeffries but this is how he describes it and how it felt:

When you get this right, development turns into a very pleasant
cycle of testing, seeing a simple thing to fix, fixing it, testing,
getting positive feedback all the way.

Guaranteed flow. And you go so fast! Try it, you'll like it.

Update: Martin incorporated the Testbrowser and Testrecorder HOWTO in his tutorial. I updated the link to point to that.

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

Sat, 03 Jun 2006

Skeleton for Plone Core packages in ZopeSkel

Thanks to Hanno, ZopeSkel now has a template for starting Plone Core packages. Hanno is using ZopeSkel for the new plone.i18n package.

Get ZopeSkel

ZopeSkel has moved to the Collective. Get the latest and greatest of ZopeSkel via this command:

easy_install http://svn.plone.org/svn/collective/ZopeSkel/trunk#egg=ZopeSkel-dev

Create a package

Remember from last time that Paste Script is useful for creating a consistent directory structure and files for you so that you can get to the actual work quickly. Plus, your projects will be ready for distribution without any additional work.

Now let's say we want to start a plone.form package. What we need to do is invoke paster create, telling it that we want to use the plone_core template. This is done using the -t command-line option. After invoking the command, we're asked for some variables:

$ paster create -t plone_core
Selected and implied templates:
  ZopeSkel#plone_core  A Plone Core project

Enter project name: plone.form
Variables:
  package:  ploneform
  project:  plone.form
Creating template plone_core
Enter namespace_package (Namespace package) ['plone']:
Enter package (The package contained namespace package (like i18n)) ['']: form
Enter version (Version) ['0.1']:
Enter description (One-line description of the package) ['']: Plone compatibility layer for zope.app.schema and zope.formlib
Enter long_description (Multi-line description (in reST)) ['']:
Enter author (Author name) ['Plone Foundation']:
Enter author_email (Author email) ['plone-developers@NOSPAMlists.sourceforge.net']:
Enter keywords (Space-separated keywords/tags) ['']:
Enter url (URL of homepage) ['']:
Enter license_name (License name) ['GPL']:
Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]:
Creating directory ./plone.form
  Recursing into +namespace_package+
    Creating ./plone.form/plone/
    Recursing into +package+
      Creating ./plone.form/plone/form/
      Copying HISTORY.txt_tmpl to ./plone.form/plone/form/HISTORY.txt
      Copying LICENSE.GPL to ./plone.form/plone/form/LICENSE.GPL
      Copying LICENSE.txt_tmpl to ./plone.form/plone/form/LICENSE.txt
      Copying README.txt_tmpl to ./plone.form/plone/form/README.txt
      Copying __init__.py to ./plone.form/plone/form/__init__.py
      Copying configure.zcml to ./plone.form/plone/form/configure.zcml
      Copying version.txt_tmpl to ./plone.form/plone/form/version.txt
    Copying __init__.py to ./plone.form/plone/__init__.py
  Copying setup.cfg to ./plone.form/setup.cfg
  Copying setup.py_tmpl to ./plone.form/setup.py
Running /usr/bin/python setup.py egg_info

Note that we typed in values for the project, package and descriptions variables only. For the rest we decided that the default was good enough. We're ready to start working on plone.form now.

Non- Plone Core packages

There's no reason why we wouldn't use the plone_core template for our own packages. After all, the name of the namespace package and that of the contained package are variables, and the directory structure might well be useful for your own project.

Updating a ZopeSkel package

Whenever the plone_core template changes, we can simply rerun the paster create command to update our project:

$ paster create -t plone_core
Selected and implied templates:
  ZopeSkel#plone_core  A Plone Core project

Enter project name: plone.form
Variables:
  package:  ploneform
  project:  plone.form
Creating template plone_core
Enter namespace_package (Namespace package) ['plone']:
Enter package (The package contained namespace package (like i18n)) ['']: form

[...]

  Recursing into +namespace_package+
    Recursing into +package+
      ./plone.form/plone/form/HISTORY.txt already exists (same content)
      ./plone.form/plone/form/LICENSE.GPL already exists (same content)
      ./plone.form/plone/form/LICENSE.txt already exists (same content)
      ./plone.form/plone/form/README.txt already exists (same content)
      ./plone.form/plone/form/__init__.py already exists (same content)
      ./plone.form/plone/form/configure.zcml already exists (same content)
      ./plone.form/plone/form/version.txt already exists (same content)
    ./plone.form/plone/__init__.py already exists (same content)
  ./plone.form/setup.cfg already exists (same content)
  ./plone.form/setup.py already exists (same content)
Running /usr/bin/python setup.py egg_info

If something had changed, we would have been presented a diff of our version of the file and the new version inside the template.

An inconvenience here is that when running paster create, we're asked for all variables again. Fortunately, there's the --config=CONFIG option that'll store all our variables in a file. Both for initial creation and for updating, our command becomes:

$ paster create -t plone_core --config=plone.form/template_vars.cfg

Extending ZopeSkel

Extending the plone_core package to fit our own needs is really easy. Let's say we want to create a new template called my_package that's based on plone_core. We want our new template to use what's already there in plone_core and add a browser package in there with __init__.py and configure.zcml files.

Inside our SVN checkout of ZopeSkel, we create this directory:

$ mkdir -p zopeskel/templates/my_package/+namespace_package+/+package+/browser

Then we add our two files:

$ edit zopeskel/templates/my_package/+namespace_package+/+package+/browser/__init__.py_tmpl
$ edit zopeskel/templates/my_package/+namespace_package+/+package+/browser/configure.zcml

Note that we create an __init__.py_tmpl file, with the _tmpl suffix because setuptools would currently not include our .py file in the distribution if the file ended with .py. So although our __init__.py_tmpl file isn't necessarily a template (nothing is substituted), we make it a Paste Script template so that it gets picked up by setuptools.

The next thing we do is wire up the my_package template so that it's available from the command-line. Inside zopeskel/__init__.py we add this:

class MyPackage(PloneCore):
    _template_dir = 'templates/my_package'
    summary = 'A Plone package that has a browser subpackage'
    required_templates = ['plone_core']

Finally, we define an entry point for our template in setup.py:

[...]

entry_points="""
[paste.paster_create_template]
basic_zope = zopeskel:BasicZope
plone_core = zopeskel:PloneCore
my_package = zopeskel:MyPackage
""",

[...]

Note that we only added the my_package entry point here.

After calling setup.py develop we're ready to create a new project with our own template:

$ python setup.py develop
[...]
$ paster create --list-templates
Available templates:
  basic_package:  A basic setuptools-enabled package
  basic_zope:     A Zope project
  my_package:     A Plone package that has a browser subpackage
  paste_deploy:   A web application deployed through paste.deploy
  plone_core:     A Plone Core project

Easy as pie!

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

Wed, 24 May 2006

Debug Script (Python) with pdb

There's a handy two-line Zope2 Product that allows pdb.set_trace() inside Script (Python) objects. Check it out here:

svn co svn://svn.zope.org/repos/main/Products.enablesettrace/trunk enablesettrace

And then put it into your Products directory. This is only for development, of course.

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

Better Plone development quality through...

  • tests
  • fewer skin customizations and monkeypatches
  • more generic code
  • motivation
  • how to get there

A presentation on how to improve the quality of your Plone development that I gave recently at Zest Software.

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

Tue, 23 May 2006

Quickstart your next Python project with Paste Script!

For your next Python project, consider using Paste Script. Paste Script helps you set up your project structure quickly so that it's ready for distribution.

Getting Paste Script

Just easy_install Paste Script like so:

easy_install PasteScript

This will download the latest Paste Script and all its dependencies from the Cheese Shop.

If you don't want easy_install to put the downloaded packages into your standard site-packages directory, consider using workingenv or look at Custom Installation Locations.

Using Paste Script

This is where it gets interesting. When we invoke the paster create command, we'll be asked a couple of questions, most of which we can answer by hitting enter and thereby using the default value:

$ paster create
Selected and implied templates:
  PasteScript#basic_package  A basic setuptools-enabled package

Enter project name: MyFancyNewProject
Variables:
  package:  myfancynewproject
  project:  MyFancyNewProject
Creating template basic_package
Enter version (Version (like 0.1)) ['']:
Enter description (One-line description of the package) ['']: This is a fancy project

...

After answering the questions, Paste Script will set up the files for our project:

Creating directory ./MyFancyNewProject
  Recursing into +package+
    Creating ./MyFancyNewProject/myfancynewproject/
    Copying __init__.py to ./MyFancyNewProject/myfancynewproject/__init__.py
  Recursing into +project+.egg-info
    Creating ./MyFancyNewProject/MyFancyNewProject.egg-info/
  Recursing into docs
    Creating ./MyFancyNewProject/docs/
  Copying setup.cfg to ./MyFancyNewProject/setup.cfg
  Copying setup.py_tmpl to ./MyFancyNewProject/setup.py
Running /usr/bin/python setup.py egg_info

Your newly started project is now ready for distribution!

Paste Script and Subversion

By the way, there's also a handy --svn-repository=REPOS argument to the paster create command which will create a basic Subversion layout for your project. Pass the Subversion directory that you want to be used as the parent of your project's directory like so:

$ paster create --svn-repository=http://mysubversionserver/myprojects/

This will create a MyFancyNewProject directory under myprojects/ and it'll create trunk, branches and tags subdirectories therein.

Pluggability

Adding your own set of templates to Paste Script is fairly simple. The Paste Script developer documentation explains how to do that.

Based on that, I've had the idea of creating a simple set of templates for quickstarting a Zope project. There's already the skeletor project which aims to do something similar for Zope 2. When I looked at skeletor though, I decided that it does a bit much and it's fairly complex. I also ran into a few tracebacks while trying to use the tool. Which led me to trying out Paste Script.

ZopeSkel project

I've started a small project which I call ZopeSkel. The only purpose of ZopeSkel is to add a couple of templates to the existing ones of Paste Script. Right now, ZopeSkel contains only one template called basic_zope, which is very bare bones. Take a look at the project's templates directory.

You can think of ZopeSkel as a minimal example of creating your own templates package for use with Paste Script. I want to look and see if I can create a good set of templates. Please tell me what kinds of templates would be helpful for you!

To install the latest ZopeSkel from Subversion do easy_install http://svn.plone.org/svn/collective/ZopeSkel/trunk#egg=ZopeSkel-dev. After installing, you can see that the list of templates available to paster create has been extended:

$ paster create --list-templates
Available templates:
  basic_package:  A basic setuptools-enabled package
  basic_zope:     A Zope project
  paste_deploy:   A web application deployed through paste.deploy

Try paster create --help to find out more about the create command.

setuptools Development Mode

When developing setuptools enabled projects, setuptool's Development Mode is essential. In Development Mode, you can edit code inside the checkout directory and immediatley see the effects of your changes when running the program. (If you make any changes to the project's setup script or C extensions, you need to run python setup.py develop).

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

Wed, 10 May 2006

Plone in an egg

My stab at packaging Plone as an egg (this links to the tarball).

Building the egg

  1. Checkout a bundle of Plone that contains all the necessary products in the Products/ subdirectory
  2. Run setup.py bdist_egg. This requires you to have setuptools installed.

The egg should be now in dist/Plone*egg, ready for installation. You can distribute your egg at this point.

Note: Currently there is a problem that prevents ATContentTypes' thirdparty package from being included. This should probably be fixed in ATContentTypes. For now, you need to put an empty __init__.py file into the Products/ATContentTypes/thirdparty directory.

Installing the egg

You can install the egg site-wide. With the effect that the Products will be available for import implicitly for every Zope 2 instance in the site. Doing this is very simple:

easy_install dist/Plone*egg

Because Zope 2 will automatically scan all packages inside Products, there is no way to control exclusion of a Product in your instance. This is less than ideal. If our Product were not to use Zope2's Products namespace (which is well doable using Rocky Burt's pythonproducts), we could have more control of what is included, using Five's new registerPackage directive. (Note that pythonproducts was merged into Five.)

Now that all packages in Plone use the Products namespace, we'll have to think about a way to deal with this. Fortunately, easy_install comes with the --multi-version command line option, which allows you to have more control over which packages are available at runtime.

Using --multi-version, we can install our egg into the instance's lib/python directory to effectively make our egg only available in that instance:

easy_install --multi-version \
             --install-dir=$INSTANCE_HOME/lib/python/ \
             --site-dirs=$INSTANCE_HOME/lib/python/ \
             dist/Plone*egg

When you install something --multi-version, client code that uses your package has to be aware of that and do an explicit import pkg_resources; pkg_resources.require(name). In our example, we need to require('Plone') somewhen in our Zope process. I had the idea of requiring packages in zcml, similiar to how pythonproducts registers ordinary Python packages as Products. There's a pending patch for pythonproducts that enables this, although pythonproducts is maybe the wrong place to implement this:

Index: src/pythonproducts/fivedirectives.py
===================================================================
--- src/pythonproducts/fivedirectives.py      (revision 26757)
+++ src/pythonproducts/fivedirectives.py      (working copy)
@@ -16,6 +16,7 @@
 """

 from zope.interface import Interface
+from zope.schema import BytesLine
 from zope.configuration.fields import GlobalObject


@@ -35,4 +36,11 @@
                     u'with a ProductContext instance',
         required=False
         )
-
\ No newline at end of file
+
+class IRequireDistributionDirective(Interface):
+    """pkg_resources.require() a distribution."""
+
+    name = BytesLine(
+        title=u'Target distribution',
+        required=True,
+        )
Index: src/pythonproducts/meta.zcml
===================================================================
--- src/pythonproducts/meta.zcml      (revision 26757)
+++ src/pythonproducts/meta.zcml      (working copy)
@@ -12,6 +12,12 @@
        handler="Products.pythonproducts.pythonproducts.registerPackage"
        />

+    <meta:directive
+       name="requireDistribution"
+       schema="Products.pythonproducts.fivedirectives.IRequireDistributionDirective"
+       handler="Products.pythonproducts.pythonproducts.requireDistribution"
+       />
+
   </meta:directives>

 </configure>
Index: src/pythonproducts/pythonproducts.py
===================================================================
--- src/pythonproducts/pythonproducts.py      (revision 26757)
+++ src/pythonproducts/pythonproducts.py      (working copy)
@@ -37,6 +37,13 @@
         args = (package,initialize)
         )

+def requireDistribution(_context, name):
+    """ZCML directive function for requiring a distribution using
+    pkg_resources.
+    """
+
+    import pkg_resources
+    pkg_resources.require(name)

 def _registerPackage(module_, initFunc=None):
     """Registers the given python package as a Zope 2 style product

After applying this patch to your pythonproducts installation, you can go ahead and include Plone in your instance using zcml. Create a $INSTANCE_HOME/etc/package-includes/plone-configure.zcml file and put the following in it:

<configure xmlns="http://namespaces.zope.org/zope"
           xmlns:five="http://namespaces.zope.org/five">
    <five:requireDistribution name="Plone" />
</configure>

Please refer to the pythonproducts README for details on where to add zcml and why.

Now start up your Zope and hopefully see Plone getting loaded.

Note that for packages which are not in the Products namespace package, i.e. for Product-less Python packages you would need to use pythonproducts' registerPackage directive as well. (Which is a good thing.) For these packages, the whole process becomes a lot easier, because you can just easy_install away and be done, or if you need instance- specific versions/packages, use --multi-version and the requireDistribution directive.

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


< February 2009 >
SuMoTuWeThFrSa
1 2 3 4 5 6 7
8 91011121314
15161718192021
22232425262728

Feed of all categories: rss rss | atom

Categories: