Category Archives: Plone

Practical collective.xdv

Last year I published an overview of collective.xdv. A new and very promising way of theming Plone. Now that we’ve used it a few times I thought I’d document some the process we went though.

Firstly read the documentation:

It’s very good and shows you the best way to structure your theme.

Our setup:

  • Plone 3.3.5
  • CMF 2.1.2
  • PIL 1.1.6

Setting Up Collective.xdv Best Practice

The collective.xdv documentation has a very good description of the best way to setup  collective.xdv read it. I won’t go in to the full details as they are well documented but the basic points are:

  • Setup a Plone product
  • Use css registry to serve the css, instead of serving through XDV. This gives you the all the advantages of managing CSS through CSS registry (compression etc).
  • Create your html/css templates.

In our setup I turned off all stylesheets but kupustyles.css, authors.css, kupuplone.css, kupudrawerstyles.css when serving through XDV. I also created a new stylesheet to pull in what we needed from the admin theme. By adding back in on a case-by-case basis you can avoid CSS conflicts with your themes styles. Of course if you’re completely mad you could decide to restyle the admin interface (good luck with that).

Snags

There were a few snags we ran into. Here’s how we fixed them:

no styling with portal_factory

We ran in to an issue with our Plone setup and portal_factory. The transformation stopped working when you added content, leaving you seeing the default plone theme. Very confusing. Apparently it’s fixed in 3.3. but for whatever reason we had to use this monkey patch:

http://webteam.medsci.ox.ac.uk/integrators-developers/portalfactorypatch

Here are some great tips for using collective.xdv as well:

http://webteam.medsci.ox.ac.uk/integrators-developers/xdvtips

IE conditionals

By default I was removing comments from both the theme and content. (<rules />) . As the IE conditionals are wrapped in comment tags I had to add them back based on their order.

<append theme='/html/head' content='/html/head/comment()[3]' />
<append theme='/html/head' content='/html/head/comment()[4]' />

Lack of applyPrefix support for Plone 3

Plone 4 has a option to parse a stylesheet for relavtive URLs and apply an absolute prefix. You’ll have to do this manually with Plone 3.

Styling the Search Box

I’m not a fan of Plone search box so it was nice to be able to just pull out the action attribute to use:

<prepend theme='//*[@id="search-form"]' content="//*[@id='portal-searchbox']/form/@action" />

Using Conditionals to Select Templates

Using Plone’s default body classes or defining your own you can specify which template to use based on class name. This is a big win as you no longer have mess around with macros or the main template. For example:

<theme href="one-column.html" css:if-content="body.one-column" />
<theme href="two-column.html" css:if-content="body.two-column" />
<theme href="three-column.html" css:if-content="body.three-column" />

Pulling in Content

You could bring in content piece-by-piece – writing rules for each element. I found this was time consuming and difficult. In the end it made more sense to pull in the all content from each column. If you want to re-work the HTML of a standard portlet it’s better to use inline XSL (more on that in the next article)

<replace content='//*[@id="portal-column-content"]/div/*' theme='//*[@id="content"]' />

Conclusion

From my perspective:

  • It gives control of the templating to the front-end dev / designer.
  • It allows working in parallel with Plone devs rather then them waiting for templates to be completed.
  • Using collective.xdv dramatically sped up the time we had a skinned site we could show to the client.
  • We cut the time we spent doing donkey work and increased the time we could spend on worthwhile development.

I’ll leave it to the Senior Developer to give the pros from an experienced Plone developer:

  • No mangling of reference HTML templates as they are implemented in TAL by Plone Devs
  • improved team workflow as HTML/CSS Designer/Dev can work in parallel with Plone Devs
  • lighter workload for Plone Devs as there is much less HTML to implement in TAL
  • reduced need to explicitly remove unwanted elements from TAL templates – they can mostly be ignored by xdv
  • flexibility in layout between pages – i.e. one-column, two-column, three-column layouts don’t require a mass of macros and modification of main_template to achieve. This can instead be pushed up to the XDV layer.

Setting the modification date of an Archetype object in Plone.

Modification dates of Archetypes objects are set automatically to the current
date and time when an object is reindexed. Usually this is useful behaviour but if
,for example, you’re importing content from elsewhere into a Plone site and you’d
like to set the modification date to be some time in the past then it’s a problem.

Heres a method that sets the standard dates of an Archetypes content type ‘obj’
to DateTime ‘dt’.

def setObjDate(obj, dt):
    """Prevent update of modification date 
       during reindexing"""
    obj.setCreationDate(dt)
    obj.setEffectiveDate(dt)
    obj.setModificationDate(dt)
    od = obj.__dict__
    od['notifyModified'] = lambda *args: None
    obj.reindexObject()
    del od['notifyModified']

The trick, based on migration code found in the plone.app.blob package, is
to mask the ‘notifyModified’ class method with a no-op lambda on our
instance, call the reindex, then drop the mask so that the class method is visible
once again.

I’ve used this successfully for importing data into a Plone 4 instance but it should work at least as far back as Plone 2.5.

Plone Conference 2010: Day 1

So it’s the end of day one halfway through day two (this took a lot longer to write than I thought!) at this year’s Plone Conference and between the two of us, we’ve seen 13 talks so far. Whilst I can’t comment on the ones that Doug has been to, I’m going to summarize my experience of today’s talks. You might also want to take a look at Rick Hurst’s summary of day 1.

Keynote: The Future of Plone by Alexander Limi & Alan Runyan

Slides | Stream

TL;DR: Plone 4 is actually pretty awesome; Deliverance/XDV is now Diazo; we need to engage more with other communities and concentrate on design for Plone 5.

In an opening keynote not dissimilar to last year’s in Budapest, Alexander Limi set out once again to summarize the previous and the next year of Plone. The major differences being, Plone 4 is now out and the heavier focus on strategic goals rather than technological ones. Lots of congratulations for Plone 4 release going so smoothly. It’s a lot faster, better out of the box and easier to install. There should be a few more minor version increases over the next year or so and as of release 4.1, Plone 3 will no-longer be supported. Looking forward to Plone 5 (which Hanno Schlichting hesitantly put a date of March 2011 on) a big deal was made of the 3 “D”s of Plone: Dexterity, Deco and Diazo; Diazo being the new, back-of-a-cigarette-packet name for XDV / Deliverance in Plone 5. Whilst Alex focussed on what will be new in Plone 5, Alan spoke of the need to kill off things that are no-longer used or are replaced by new technologies, one example being writing restricted Python through the web:

“Who uses editing Restricted Python through the web?”

The sound of a room full of people putting no hands up.

Laughter.

One thing that particularly threw me as a new developer was the number of different ways to do things and to a certain degree, I think a limiting of these options is a good thing.

The need to make Plone more appealing to the decision makers was also expressed. Alex believes that over the next few years, designers will be making the choice of CMS to use (a company goes to a designer for a website, they come up with a great design, then have to pick the CMS onto which that design should be applied by developers or a separate company). Other places to focus on getting the Plone word out there: other conferences, local user groups and getting Plone available to people using cheaper hosting solutions, such as getting a cPanel installer working, a stark contrast to last year saying “we’re not really in the same market as Joomla and Drupal and WordPress [...] it will always be easier to pay $5 and get a PHP host somewhere; that’s not something we can fight”.

Mad About Mobile by Mikko Ohtamaa

Slides | Stream

TL;DR: Your clients want mobile sites, if they don’t you should persuade them. WebAndMobile from mFabrik will help you solve a lot of common problems and add a lot of cool features so you can deliver.

Mikko opened by saying something along the lines of, “Your clients want mobile sites, if they don’t you should persuade them” and I couldn’t agree more. Not only will a mobile site increase the number of users you can reach (or the times at which they can use your website), it can also add some really cool features (Mikko lists geolocation, touch and multi-touch events & phone interactions like click to call & contact card download). Furthermore it’s a good way to provide a minimal version of your site to users who perhaps have problems with their sight or mobility.

He touched on the different levels of mobilization that are achievable starting with custom CSS and going all the way up to writing a completely new mobile app.

The Plone extension route provides a nice middle ground that will get you most of what you probably want from a mobile version of your Plone site (mobile browser detection, image resizing and serving different content for mobile platforms). Mikko has been working on WebAndMobile for the past year and a half, it actually has documentation and there are plans to merge in common components of Infrae’s mobi.* group of packages. It is currently live on about 6 Plone sites and has some crossover capability for other frameworks such as Django. It:

  • Will automatically redirect to a mobile site based on information in the HTTP request and can scale the site to the features of the user’s platform;
  • Provides support for theming different platforms with different capabilities;
  • Allows integration of mobile-features such as opening a waypoint in a smartphone’s maps or navigation application;
  • Provides the option of serving alternate or no content for content type fields and integrates seamlessly into the existing editor interface.

Neat. For me it looks like the best way to get most of the way towards adding a mobile version of your Plone site. Whilst it won’t be a free-ride, it’s a hell of a good step in the right direction.

High Performance Sites Made Easy by Matthew Wilkes

Slides | Stream

TL;DR: Everything you thought before about optimization is probably wrong. You need to use the catalog less, work off real-world numbers rather than profiling and cache the hell out of everything you can, no matter how insignificant it may seem.

For me this was probably the most useful talk of the day. It really busted quite a few myths I believed in and exposed new techniques that I thought weren’t possible with Plone, namely Edge-Side Includes in Varnish. The talk started with a brief summary of what is and isn’t important, backed up by some interesting stats. For example, whilst not waking objects is fine as a rule of thumb, it’s actually slower to use the catalog to access data up to about 50 objects. There was a big focus on optimization based on real data and putting it off until you can get some. Matthew eschews profiling in favour of analysis of page load time and server logs of normal site usage. One thing which will be of particular use is the tool Jarn have written for analyzing HAProxy logs.

Catalog tips included removing as many indexes as possible, generating better brains using adapters for the ICatalogBrain interface and being particularly careful with ZODB cache size: walking the catalog may in fact clear the ZODB cache given the huge number of tiny objects the catalog uses.

Quick wins for caching can be achieved by implementing ESIs (particularly implementing them from BrowserView __call__ methods so they are more flexible and can be disabled quickly in case of emergency) and avoiding status messages (not only does they make a page not cacheable by Varnish, but Varnish caches that it isn’t cacheable for 3 mins!).

Finally he makes the excellent point that it can be worth haggling with the client over arbitrary decisions they may have made about things such as list size, pagination, long form-based processes & workflow, all of which can inhibit caching.

Lose weight now, ask me how! by Roché Compaan

Slides | Stream

TL;DR: The catalogs are massive bottlenecks; we rewrote some common parts of Plone that overuse them.

Continuing in a similar vein to Matthew Wilke’s talk, but taking a more extreme approach, Roché Compaan almost seems like he is out to destroy the catalogs, and not without justification. He began by asking the question, “can Plone scale to 10 million objects?” Starting at the lowest level, he produced some benchmarks of the ZODB using collective.zodbbench in 2007, compared them to similar operations for Postgres and found that ZODB performs extremely well, holding steady at about 250 writes per second achieved on a sample database of 10m objects.

When it came to analyzing Plone (using ZopeProfilerexperimental.catalogqueryplan and ZODB.FileStorage.fsdump) he found some pretty horrifying stats about the catalog. For example, 90% of a Data.fs for a database of 10,000 content objects was dedicated to objects supporting the catalogs. Unfortunately he didn’t seem to have any stats on how the catalog affects speed.

upfront.diet is a suite of products that offer replacements for parts of Plone that either cut out catalogs entirely or drastically reduce their usage. The most useful of these seem to be the upfront.simplereferencefield and upfront.catalogblacklist. upfront.catalogblacklist seems like something that should have been offered in Plone to begin with; it allows the developer to limit the indexing of specific content types through genericsetup. upfront.simplereferencefield is a replacement for the Archetypes reference field that doesn’t use the UID catalog. According to his stats, importing 50k objects using the archetypes reference field took 50 mins, while importing the same data set using the upfront.simplereferencefield took 5 mins. Impressive results, but this slash and burn approach to catalog usage leaves me uneasy, particularly when it’s something that is under consideration for Plone 5 anyway.

Others

Other talks I went to were Giving light to dark corners of z3c.form by Rok Garbas which was a good, quick intro to what seems to be the most flexible of all the Plone form frameworks; Laying Pipe with Transmogrifier by Clayton Parker which was a brief summary of the features of collective.transmogrifier

which seems like a very powerful tool for importing data from various sources, but as Rick Hurst says, probably a bit heavyweight for what most people will want; and Tools and techniques for a successful Plone project by Martin Aspeli in which he shared a sneak preview of some of the tools and techniques he will be recommending in the new Plone 4 edition of his book.

Finally, at the end of day 1 was the guest keynote from Richard Noble, a very entertaining affair on the spirit of engineering and how teamwork matters far more than any amount of funding you might have.

An excellent start to the conference!

Announcing FuncBrows – A browser testing tool

For the short version: System web browser testing abstraction layer. Get it here

For the last month or so, I have been heavily investigating various functional browser testing tools, with the aim of adding them to our Continuous Integration build.

The History

I settled on using zc.testbrowser for writing quick, functional tests that can be added to the end of a unit test run. As testbrowser isn’t a full browser in itself, it’s fast to run tests with, and can easily be integrated with the Zope and Plone functional tools.
However, for a full suite of integration tests, testbrowser isn’t a great fit. It doesn’t support javascript, and won’t tell you that ‘The login button is missing in IE6’, or that ‘Firefox 3 can’t access the profile changer’. For this type of test, the current leader is Selenium, which can instrument and drive real browsers (IE, Firefox, Chrome, Safari), in order to perform more accurate real world tests.
Selenium is currently undergoing a massive revamp in order to add better functionality and clean up the API (including a mode that will work similar to testbrowser), however this means that we are currently stuck with the older, stable version, as it has python bindings and more documentation.

So, given these two tools, I wrote a simple suite of tests for a project. They registered a user, logged in, logged out, and changed a user profle. Not massively complex, but it’s often surprising how many times such simple processes can be broken, and you won’t notice as you tend to always use the same test user details.

This was all well and good, and everyone was happy and it was sunny.

The Problem

The problem then became, that although developers can write testbrowser scripts fairly easily, and run them quickly, selenium is a lot more heavyweight, requiring selenium installs, multiple browsers and virtual machines to run a full test.

Fundamentally, the selenium API is very different from testbrowser, and asking people to write both was never going to happen.

This meant that selenium was added to the CI build, but the developers would never usually run the tests themselves, creating a disconnect between the current tests that the developers would run as part of their unit test suite, and what would be tested more heavily with the CI build.

The Solution

I (with a lot of help from other people, some ‘creative language’, and some frustration) created FuncBrows. This is a simple, lightweight abstraction tool over both testbrowser and selenium, that can easily be extended to add more tools to it, when required (selenium v2 and twill are on the target list).
It can easily be included, and configured in one line, with a base set of tests that can then be run by every tool, as required.

This means that the developers can write fast tests for their own use, and the exact same code can then be reused for more complete browser testing later in the system tests. A quick, simple way to smoke test for browser issues

There is a samples directory in the github repository, with a simple example of how to set up the tests so that they can be run with either the python standard test runner, or nosetests.
It’s fairly simple, and can’t do any advanced stuff, it only progressed to the stage where we could dogfood our existing tests, I expect the API to grow slightly as we need more functionality from it.
Patches and issues gratefully accepted at the github page.

Get the bits here: Isotoma Github
Or ‘easy_install FuncBrows’

Plone Theming or: How I Learned to Stop Worrying and Love collective.xdv

Recently I’ve been tasked with looking at how we can improve our Plone theming process.

One of the problems that most teams come across on any web project is how to spend less time doing the basics and more time solving the unique problems that each project throws up. This seems to be especially true when it comes to skinning / implementing user interfaces. No matter what framework / CMS I’ve used (and I’ve used plenty) it’s often hard to square the circle between what we want as output and what is actually produced.

Another aspect that can eat up time is having to implement user interface changes during development. Even with the best sign-off procedures, designs, and by extension HTML templates are often subject to change. With that in mind the key objectives we are looking for in a theming method are:

  • easily portable between projects.
  • full control over CSS/HTML and JS output.
  • working in parallel with the development team.

So lets look at the various theming options for Plone.

“Plone theming is getting a bit complicated”

You’re not wrong. From what I can see you have 2 options:

  1. Write a custom stylesheet. It’s amazing what you can do with CSS, but that alone won’t cut it. We need to able to specify the HTML output to meet our high standards of accessibility and design.
  2. Create a ‘vanilla’ theme product. Creating a Plone theme is not for the faint hearted and to be honest it had me stumped. You really need to have a solid understanding of Plone and Zope to create anything worthwhile and while that is not necessarily a problem it’s certainly not my area of expertise.

I could probably grab some developer time here at Isotoma to help me put together this ‘vanillla’ product, but even that doesn’t answer our needs in the level of flexibility we require. There must be an easier way….

Deliverance / Collective.xdv

The future of Plone theming lies in Deliverance / Collective.xdv and will be at the core of Plone 4 theming (so I’m told). You can start using it now though. (see this excellent tutorial to get started )

It took a little effort to get a working buildout, mainly because I couldn’t get lxml working on my mac (necessary for collective.xdv). So I installed it on an Ubuntu VM which worked just fine.

Once I’d got it working it didn’t take me long to realise the potential of this new way of theming. In a nutshell, it allows you to have whatever output you want. Not only that but it allows template development to happen separately and in tandem with the main development effort.

Let’s have a quick look at how it works. At it’s simplest level you have 2 files: theme.html and rules.xml. The theme.html file is a standard html template and you can write this however you want. It is the rules file where it gets interesting. I won’t go in to the full details (see here for a full description) but here are some examples of what you can do.

Replace content:

<replace content='//*[@id=”content”]' theme='//*[@id=”content-area”]' />

this replaces the element in the theme.html with whatever content Plone produces within #content element.

Append / prepend content:

<append content='/html/head/style' theme='/html/head' />

this adds all the styles from Plone.

Discard content:

<drop theme='/html/head/comment()' />

This removes comments form the theme.html appearing in the site.

It uses Xpath, something that I’m familiar with and very easy to learn. With deliverance it gets even easier because you can use CSS 3 selectors. All-in-all you have a very powerful way of theming Plone whilst having a fantastic level of separation and flexibility.

I’m very hopeful that collective.xdv / Deliverance will be the solution we are looking for and I’m really looking forward to using it on forth coming projects.

Location of Zope/ZEO transient caches

When Zope connects to ZEO it is configured with a database cache, where objects are cached by Zope so that it doesn’t have to constantly return to ZEO. These caches can be transient (they don’t persist past a Zope restart) or persistent (where they do).

If all you do is uncomment the example ZEO client configuration in your zope.conf you’ll have a 20MB transient cache. If you follow one of the many buildout recipes on the web you’ll likely have a transient cache of anywhere from 30MB (plone.recipe.zope2instance) up to 300MB (from this howto on plone.org).

Zope uses the Python tempfile module to decide where to put these transient caches, which on Debian defaults to /tmp. Our default production server installation has /tmp as a subdirectory of /, with the root partition being only 1GB. This means we have a maximum of about 400MB for temporary files on our servers.

With the default 20MB or 30MB this is fine, even in multiple Zope/ZEO installations on the same box. However, when we recently tried to up the size of the caches on a system that needed it we quickly found ourselves running out of diskspace in the root partition, which in turn caused some very strange behaviour, ultimately resulting in the site being unavailable.

The trick is to move these transient files to a more sensible location (like /var/tmp). You can do this (with thanks to mauro on zodb-dev) by setting an environment variable in your zope.conf, either manually:

<environment>
  TMPDIR /var/tmp
</environment>

Or in your buildout:

[instance]
recipe = plone.recipe.zope2install
...
environment-vars =
     TMPDIR /var/tmp

Javascript localization within Plone

For a while now, I’ve been trying to think of the best way to get localized strings into Javascript under Plone. Many existing packages and parts of Plone use one Javascript file per language, containing all translations. Whilst this is effective, it doesn’t “feel right” having all your translations distributed to the user on each page load, much less having them drawn from two different sources. Worse still (in my mind) is having translations dumped out into hidden HTML elements and then recalled by Javascript using getElementById or some such.

The solution I’ve eventually settled on is one that combines AJAX and client-side caching in cookies to minimize page load time. The implementation consists of a single view, a Javascript file and a bunch of XML & ZCML to tie it all together.

The powers that be here at Isotoma, have kindly agreed to let me open source this under the Apache 2.0 license.

Full documentation can be found for the code can be found in the README.txt, however I’ve included a quickstart guide below.

Continue reading

Beginning development with Plone 4 & Dexterity

Over the past few days, I’ve been tinkering with the latest alphas of Plone 4, particularly with an eye to trying out Dexterity on the latest version.

I started out, as many people will, by downloading the unified installer which will install Python 2.6, Zope 2.12 and the Plone 4.0 alpha for you. After a few teething problems with multiple versions of Python on my Hardy host, I had my Plone install up and running.

First impressions among myself and my colleagues here at Isotoma were that firstly, it was a heck of a lot faster than its predecessor. In fact, John Stahl recently blogged that Plone 4 is potentially three times faster than Drupal, Joomla and WordPress. The other main, marked difference was the default theme, which is a lot slicker, though in my own opinion with its blocks of bright colours and rounded corners, a little too overtly “Web 2.0” (insert air-quotes here).

My next stop was Martin Aspeli’s Dexterity developer manual which whilst up-to-date for the current stable release of Plone, required some tweaking to get going with Plone 4.

The unified installer, by default, makes use of several config files for buildout, which keeps a lot of the core settings in separate files (base.cfg & versions.cfg). I hear that roadrunner is almost ready for Plone 4, but it’ll be a little while before we’re getting it without checking out the source so that had to be chopped. The extends entry for Dexterity also required updating to the latest alpha.

Otherwise, things went very straightforwardly. My buildout.cfg for use with the unified installer can be found below the fold.
Continue reading

Useful Plone template debugging functions

As Plone developers, a lot of the problems we have when writing code and templates are only revealed with cryptic, sometimes misleading error messages from somewhere way down the stack from their underlying cause, if at all. When an error is raised, by some template rendering, Zope does provide some useful traceback information specifying the template with line numbers and expressions and whatnot. But why shouldn’t we be able to access this information without raising an error? For example, to diagnose security or redirection problems that aren’t necessarily obvious even with extra logging & verbose security enabled.

The functions provided below allow the developer to gather this kind of feedback and output wherever he or she wishes, without having to provide any arguments that might not always be easy to get from the current part of source code. They work under Zope 2.7 but are untested under other versions. If you do try them out on other versions, please report back in the comments if they do work!

import sys
from Products.CMFCore.utils import getToolByName
from zope.tales.tales import TALESTracebackSupplement

def get_current_template_position():  
    """ If called from a stack frame which has been called from template evaluation, 
        returns a tuple of template filename, line number, column number and 
        TALES expression closest in the stack to the caller. Otherwise, returns None. 
    """  
    i = 0  
    curframe = sys._getframe(i)  
    while True:  
        locals = curframe.f_locals  
        globals = curframe.f_globals  
        if '__traceback_supplement__' in locals:  
            # Use the supplement defined in the function.  
            tbs = locals.get('__traceback_supplement__')  
        elif '__traceback_supplement__' in globals:  
            # Use the supplement defined in the module.  
            # This is used by Scripts (Python).  
            tbs = globals.get('__traceback_supplement__')  
        else:  
            tbs = None  
        if tbs is not None:  
            factory = tbs[0]  
            args = tbs[1:]  
            try:  
                supp = factory(*args)  
            except:  
                continue  
            if type(supp) is TALESTracebackSupplement:  
                return (supp.context, supp.source_url, supp.line, supp.column, supp.expression)  
  
        i=i+1  
        try:  
            curframe = sys._getframe(i)  
            if curframe is None:  
                return None  
        except:  
            return None  
  
def dump_current_template_position(context=None, return_string=False):  
    """ When called, attempts to print to the console the URL of the current request, the 
        authenticated user, the currently executing template file, the line and column 
        currently being evaluated in the file and the expression being evaluated. 
 
        Will not print if called from a stack frame which has been called from template 
        evaluation. May not print if called from a .cpy or .vpy file, depending on 
        permissions to 'print'.
        
        Wherever possible, this function should be called with the 'context' arguement
        specified.
 
        If the optional argument 'return_string' is set to True, the function returns the 
        message that would be output, rather than printing. 
    """  
    tpos = get_current_template_position()  
    if tpos is not None:  
        (ctx, template, line, col, expr) = tpos  
        url = 'Unknown'
        if context is not None:
            try:  
                request = hasattr(context, 'request') and context.request or context.REQUEST  
                url = request.get('ACTUAL_URL')  
            except AttributeError:
                pass
        if url == 'Unknown':
            try:  
                request = hasattr(ctx, 'request') and ctx.request or ctx.REQUEST  
                url = request.get('ACTUAL_URL')  
            except AttributeError:
                pass
                
        member = 'Unknown'
        if context is not None:
            try:
                mtool = getToolByName(context, 'portal_membership')
                member = mtool.getAuthenticatedMember()  
            except AttributeError:
                pass
        if member == 'Unknown':
            try:
                mtool = getToolByName(ctx, 'portal_membership')
                member = mtool.getAuthenticatedMember()  
            except AttributeError:
                pass
            
        output = "\tURL: %s\n\tAuth'd as: %s\n\tFile: %s\n\tLine: %s\n\tColumn: %s\n\tExpression: %s" % (url, member, template, line, col, expr)  
        if return_string:  
            return output  
        print output

This may also be called from templates, provided the template has sufficient permissions to call the module it lies in:

<tal:block tal:define="dummy python:modules['myproject.app.utils'].dump_current_template_position(context)" />

Or, as it is mostly used, from code called by templates, simply by importing the function(s) as necessary and calling them with options of your choice. If calling from .cpy or .vpy files, the print command may not work properly, so the dump_current_template_position function may be called with the optional argument return_string set to True and then the result may be logged or printed using alternate methods.

Get a content type class by name in Zope

I recently had the problem of finding out if a content type in Plone implemented a certain interface, but only given the name of the content type rather than an instantiated object or its class. Whilst it’s easy to create an instance given a content type name, using the Portal Type Tool, creating an instance to test and then deleting it felt wrong. Unfortunately the Types Tool seems to provide no easy way of determining the class of a given type.

The solution comes from a combination of the Portal Types Tool’s type information and the Archetypes Tool’s information about the implementation:

from Products.CMFCore.utils import getToolByName

def has_interface(portal, typeName, interface):
    """ Portal is the root portal object, typeName is a
        string such as 'MyDocumentType' and interface
        is the interface class to be tested against. """

    pt = getToolByName(portal, 'portal_types')
    at = getToolByName(portal, 'archetype_tool')
    typeinfo = pt.get(typeName)
    if typeinfo:
        package = typeinfo.product
        type = at.lookupType(package, typeName)
        if type:
            klass = type['klass']
            return interface.isImplementedByInstancesOf(klass)
    return False