Tuesday, December 20, 2011

Hiding uninstall profiles using Grok

Tired of seeing your uninstall profile listed even when your package has not being installed yet?

If you have five.grok among the dependencies of your package in setup.py, you can put the following code in a setuphandlers.py file:

from five import grok

from Products.CMFPlone.interfaces import INonInstallable


class HiddenProfiles(grok.GlobalUtility):

    grok.implements(INonInstallable)
    grok.provides(INonInstallable)
    grok.name('your.package')

    def getNonInstallableProfiles(self):
        profiles = ['your.package:uninstall']
        return profiles

Remember that you need to Grok your package using the following line in your configure.zcml:

<grok:grok package="." />

This cool tip has been brought to you by Érico Andrei; enjoy it!

Friday, November 18, 2011

Thursday, October 13, 2011

Cómo habilitar la selección y copia de texto en el sitio de El Universal

Hace un rato me topé con la novedad de que algunas páginas de El Universal no permiten seleccionar texto para copiarlo.

Al principio pensé que se trataba de algún script pero pronto descubrí que se era otra cosa: la inclusión en la hoja de estilo de la página de los seudoelementos -moz-user-select y -moz-user-focus.

Si usas Firefox, la solución es muy sencilla: crea un archivo userContent.css dentro la carpeta chrome de tu perfil y agrega las siguientes líneas:

* { -moz-user-select: auto !important }
* { -moz-user-focus: normal !important }


Reinicia tu navegador y listo.

Que nadie coarte tu derecho a compartir conocimiento.

Tuesday, August 2, 2011

Displaying (and filtering) the contents of a folderish content type

If you need to list the contents of a folderish content type you can include something like this in your page template:

<fieldset id="folder-listing">
    <legend i18n:translate="">Contents</legend>
    <tal:block define="listing_macro context/folder_listing/macros/listing">
        <metal:use_macro use-macro="listing_macro" />
    </tal:block>
</fieldset>

Note that listing is a huge macro inside the skins/plone_content/folder_listing.pt template in the CMFPlone product.

You can even do things like content filtering or limiting the number of items shown with this macro:

<fieldset id="folder-listing">
    <legend i18n:translate="">Contents</legend>
    <tal:block define="listing_macro context/folder_listing/macros/listing;
                       contentFilter python:{'portal_type': ['File']};
                       limit_display python:5">
        <metal:use_macro use-macro="listing_macro" />
    </tal:block>
</fieldset>

Enjoy!

(Tested under Plone 4.1)

Wednesday, July 6, 2011

Thursday, March 10, 2011

Redirecting log output to sys.stdout on tests

Use the following code inside your tests/base.py file if you need to redirect the log output to sys.stdout for debugging purposes:

import logging
import sys

logger = logging.getLogger('YOUR LOGGER NAME')
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)

This way you can see debug(), info(), warning(), error() and critical() messages printed in the console.

More information: Logging facility for Python and Logging on Plone.

Friday, January 28, 2011

An Excel source pipeline section for collective.transmogrifier

Using xlrd, and based on CSV source section, I've written a pipeline section to read data stored inside Excel spreadsheets.

The code looks like this:

import xlrd

    from zope.interface import classProvides
    from zope.interface import implements

    from collective.transmogrifier.interfaces import ISection
    from collective.transmogrifier.interfaces import ISectionBlueprint
    from collective.transmogrifier.utils import resolvePackageReferenceOrFile


    class ExcelReader:
        def __init__(self, f, s, *args, **kwds):
            self.fieldnames = None
            book = xlrd.open_workbook(f)
            sheet = book.sheet_by_name(s)
            self.reader = list()
            for row in range(0, sheet.nrows):
                self.reader.append([sheet.cell_value(row, col)
                                    for col in range(0, sheet.ncols)])
            self.reader = iter(self.reader)

        def __iter__(self):
            return self

        def next(self):
            row = self.reader.next()
            if self.fieldnames is None:
                self.fieldnames = row
                row = self.reader.next()
            return dict(zip(self.fieldnames, row))


    class ExcelSource(object):
        classProvides(ISectionBlueprint)
        implements(ISection)

        def __init__(self, transmogrifier, name, options, previous):
            self.previous = previous

            filename = resolvePackageReferenceOrFile(options['filename'])
            sheet = options['sheet']

            self.reader = ExcelReader(filename, sheet)

        def __iter__(self):
            for item in self.previous:
                yield item

            for item in self.reader:
                yield item

The pipeline section assumes that the field names are in the first row of the spreadsheet. Note also the use of iter() to convert the list of rows into an iterator.

To use the pipeline section you only need to add something like this in your transmogrifier's configuration:

[excelsource]
blueprint = your.package.excelsource
filename = excel_book
sheet = sheet_inside_the_book

Remember to register the utility in your configure.zcml file:

<utility
    component="your.package.ExcelSource"
    name="your.package.excelsource"
    />

xlrd supports Excel spreadsheets up to version 2007.