2015-04-11

kotti_multilingual

kotti_multilingual is a package still in an early stage of development that adds to the Kotti CMS (http://kotti.pylonsproject.org/) multilingual capabilities. It is neither feature complete nor can be considered API stable: so things will change!

You can find various fixes on this fork (a PR is still in the review phase):

How it works

First of all you should add a LanguageRoot folder in your root site. It is like the standard folderish Document, but with an editable Language attribute where you set the language code (eg: en, it, etc).

Once you have created two or more language folders (with >2 languages there is a problem with the translation link actions at this time of writing) you can add your contents and translate them.

The translate menu prompts a translate into italian action from  /en/welcome
If you click on the translate into action, it will create a translated instance in /it/welcome (you can rename it later in /it/benvenuto or whatever you like) and you'll be redirected to a regular edit form prefilled with the english fields values.

Once saved, you can switch to the existing translation and navigate among languages as shown in the following picture:

You can switch to the existing English translation
kotti_multilingual supports the quite advanced concept of language independent fields: a field whose values should be inherited by translations, only editable on the root translation.

You can see for example a select widget in edit mode on the root translation:
And the same field in readonly mode on the translated object:

See the kotti_multilingual.widget.i10n_widget_factory code for more info.

Code examples

And now code examples.

resources.py

You can define language independent fields in your type_info attribute on your resource.
class YourResource(...):

    ... 

    type_info = Document.type_info.copy(
        ...
        language_independent_fields= ['course_sku',],
        )

views/edit.py

The edit form does not require changes, you just need to apply the i10n_widget_factory on your language independent fields (in some particular cases you need a bit more complex setup when you have to deal with not null column, required fields, etc). In these particular cases you'll have to play with get_source (kotti_multilingual.api.source) and put the widget in readonly mode. If you experience problems cloning select widgets you might have to migrate to deferred widgets (that creates a new widget instance each time) and set the widget mode in readonly when needed.

from kotti_multilingual.widget import i10n_widget_factory
...
from kotti_multilingual.api import get_source 
@colander.deferred
def deferred_widget(node, kw):
    request = kw['request']
    context = request.context

    ...

    widget = SelectWidget(values=available_tags, multiple=True)
    if get_source(context) is not None:
        widget.readonly = True
    return widget


class YourResourceSchema(colander.Schema):

    course_sku = colander.SchemaNode(
        colander.String(),
        title=_(u"Course SKU"),
        missing=u"",
        widget=i10n_widget_factory(TextInputWidget),
        )


class YourResourceAddForm(ImageAddForm):
    schema_factory = YourResourceSchema
    ...

    def get_bind_data(self):
        bind_data = super(YourResourceAddForm, self).get_bind_data()
        # we tell to the i10n_widget_factory that this is an addform,
        # so our widgets will be shown as usual in edit mode
        bind_data['addform'] = True
        return bind_data

Final thoughts

Yes, it is a very very young package but very promising!
It is not complete and probably it never will be complete because SQLAlchemy is huge and I think it is not possible to cover all the possible SQLAlchemy combinations.

For example this fork includes support for the SQLAlchemy's association_proxy feature and language independent fields (in this case the copy_properties_blacklist attribute on your resource is your friend).

This is open source, dude: if you need something that is not yet covered, just fork kotti_multilingual, implement the missing parts and share with others!

Update 20150427

Merged and released new version of kotti_multilingual on PyPI https://pypi.python.org/pypi/kotti_multilingual/0.2a3.
Development happens on https://github.com/Kotti/kotti_multilingual now.

All Kotti posts published by @davidemoro:

2015-04-08

Pip for buildout folks

... or buildout for pip folks.

In this article I'm going to talk about how to manage software (Python) projects with buildout or pip.

What do you mean for project?
A package that contains all the application-specific settings, database configuration, which packages your project will need and where they lives.
Projects should be managed like a software if you want to assure the needed quality:
This blog post is not:
  • intended to be a complete guide to pip or buildout. If you want to know more about pip or buildout
  • talking about how to deploy remotely your projects

Buildout

I've been using buildout for many years and we are still good friends.
Buildout definition (from http://www.buildout.org):
"""
Buildout is a Python-based build system for creating, assembling and deploying applications from multiple parts, some of which may be non-Python-based. It lets you create a buildout configuration and reproduce the same software later. 
"""
With buildout you can build and share reproducible environments, not only for Python based components.

Before buildout (if I remember well the first time I get started to use buildout was in 2007, probably during the very first Plone Sorrento sprint) it was a real pain sharing a complete and working developing environment pointing to the right version of several repositories, etc. With buildout it was questions of minutes.

From https://pypi.python.org/pypi/mr.developer.
Probably with pip there is less fun because there isn't a funny picture that celebrates it?!
Buildout configuration files are modular and extensible (not only on per-section basis). There are a lot of buildout recipes, probably the one I prefer is mr.developer (https://pypi.python.org/pypi/mr.developer). It allowed me to fetch different versions of the repositories depending on the buildout profile in use, for example:
  • production -> each developed private egg point to a tag version
  • devel -> the same eggs point to the develop/master
You can accomplish this thing creating different configurations for different profiles, like that:
[buildout]
...
[sources]
your_plugin = git git@github.com:username/your_plugin.git
...
I don't like calling ./bin/buildout -c [production|devel].cfg with the -c syntax because it is too much error prone. I prefer to create a symbolic link to the right buildout profile (called buildout.cfg) and you'll perform the same command both in production or during development always typing:
$ ./bin/buildout
This way you'll avoid nasty errors like launching a wrong profile in producion. So use just the plain ./bin/buildout command and live happy.

With buildout you can show and freeze all the installed versions of your packages providing a versions.cfg file.

Here you can see my preferred buildout recipes:
Buildout or not buildout, one of the of the most common needs it is the ability to switch from develop to tags depending on you are in development or production mode and reproduce the same software later. I can't figure out to manage software installations without this quality assurance.

More info: http://www.buildout.org

Pip

Let's see how to create reproducible environments with develop or tags dependencies for production environments with pip (https://pip.pypa.io/en/latest/).

Basically you specify your devel requirements on a devel-requirements.txt file (the name doesn't matter) pointing to the develop/master/trunk on your repository.

There is another file that I call production-requirements (the file name doesn't matter) that it is equivalent to the previous one but:
  • without devel dependencies you don't want to install in production mode
  • tagging your private applications (instead of master -> 0.1.1)
This way it is quite simple seeing which releases are installed in production mode, with no cryptic hash codes.

You can use now the production-requirements.txt as a template for generating an easy to read requirements.txt. You'll use this file when installing in production.

You can create a regular Makefile if you don't want to repeat yourself or make scripts if you prefer:
  • compile Sphinx documentation
  • provide virtualenv initialization
  • launch tests against all developed eggs
  • update the final requirements.txt file
For example if you are particular lazy you can create a script that will create your requirements.txt file using the production-requirements.txt like a template.
This is a simple script, it is just an example, that shows how to build your requirements.txt omitting lines with grep, sed, etc:
#!/bin/bash

pip install -r production-requirements.txt
pip freeze -r production-requirements.txt | grep -v mip_project | sed '1,2d' > requirements.txt
When running this script, you should activate another Python environment in order to not pollute the production requirements list with development stuff.

If you want to make your software reusable and as flexible as possible, you can add a regular setup.py module with optional dependencies, that you can activate depending on what you need. For example in devel-mode you might want to activate an entry point called docs (see -e .[docs] in devel-requirements.txt) with optional Sphinx dependencies. Or in production you can install MySQL specific dependencies (-e .[mysql]).

In the examples below I'll also show how to refer to external requirements file (url or a file).

setup.py

You can define optional extra requirements in your setup.py module.
mysql_requires = [
    'MySQL-python',
    ]

docs_requires = [
    'Sphinx',
    'docutils',
    'repoze.sphinx.autointerface',
]
...

setup(
    name='mip_project',
    version=version,
    ...
    extras_require={
        'mysql': mysql_requires,
        'docs': docs_requires,
        ... 
        },

devel-requirements.txt

Optional extra requirement can be activated using the [] syntax (see -e .[docs]).
You can also include external requirement files or urls (see -r) and tell pip how to fetch some concrete dependencies (see -e git+...#egg=your_egg).
-r https://github.com/.../.../blob/VERSION/requirements.txt
 
# Kotti
Kotti[development,testing]==VERSION

# devel (to no be added in production)
zest.releaser

# Third party's eggs
kotti_newsitem==0.2
kotti_calendar==0.8.2
kotti_link==0.1
kotti_navigation==0.3.1

# Develop eggs
-e git+https://github.com/truelab/kotti_actions.git#egg=kotti_actions
-e git+https://github.com/truelab/kotti_boxes.git#egg=kotti_boxes
...

-e .[docs]

production_requirements.txt

The production requirements should point to tags (see @VERSION).
-r https://github.com/Kotti/Kotti/blob/VERSION/requirements.txt
Kotti[development,testing]==VERSION 

# Third party's eggs
kotti_newsitem==0.2
kotti_calendar==0.8.2
kotti_link==0.1
kotti_navigation==0.3.1

# Develop eggs
-e git+https://github.com/truelab/kotti_actions.git@0.1.1#egg=kotti_actions
-e git+https://github.com/truelab/kotti_boxes.git@0.1.3#egg=kotti_boxes
...

-e .[mysql] 
requirements.txt
The requirements.txt is autogenerated based on the production-requirements.txt model file. All the installed versions are appended in alphabetical at the end of the file, it can be a very long list.
All the tag versions provided in the production-requirements.txt are automatically converted to hash values (@VERSION -> @3c1a191...).
Kotti==1.0.0a4

# Third party's eggs
kotti-newsitem==0.2
kotti-calendar==0.8.2
kotti-link==0.1
kotti-navigation==0.3.1

# Develop eggs
-e git+https://github.com/truelab/kotti_actions.git@3c1a1914901cb33fcedc9801764f2749b4e1df5b#egg=kotti_actions-dev
-e git+https://github.com/truelab/kotti_boxes.git@3730705703ef4e523c566c063171478902645658#egg=kotti_boxes-dev
...

## The following requirements were added by pip freeze:
alembic==0.6.7
appdirs==1.4.0
Babel==1.3
Beaker==1.6.4
... 

Final consideration

Use pip to install Python packages from Pypi.

If you’re looking for management of fully integrated cross-platform software stacks, buildout is for you.

With buildout no Python code needed unless you are going to write new recipes (the plugin mechanism provided by buildout to add new functionalities to your software building, see http://buildout.readthedocs.org/en/latest/docs/recipe.html).

Instead with pip you can manage also cross-platform stacks but you loose the flexibility of buildout recipes and inheritable configuration files.

Anyway if you consider buildout too magic or you just need a way to switch from production vs development mode you can use pip as well.

Links

If you need more info have a look at the following urls:
Other useful links:

Update 20150629

If you want an example I've created a pip-based project for Kotti CMS (http://kotti.pylonsproject.org):

2015-04-01

How to choose your CMS

This article is dedicated to non Python folks searching for a good CMS because I've seen too many times people taking bad decisions.

If you are searching for a CMS solution or are you writing a custom web application with content management features inside, you should consider also one of the existing solutions built with Python before choosing your platform. Even if your core business is based on different technologies or other programming languages like Java or PHP.

I'm not telling that you have to choose Python solutions, I'm just suggesting you to start with a 360 degrees serious software selection before choosing.

Obviously the final choice depends on what you have to do: a lot of times a Wordpress site with a few dollars theme and a couple of third party plugins is good enough.

But if you are plan to build something more complex that involves:
  • top level security solutions 
  • complex security requirements 
  • extensibility without having to fork the existent code
  • heavy, but still maintainable, customizations in core logics
  • you are not going to build a website, but something of more complex like an intranet
  • you are going to build something that can evolve for covering future changes without requiring a complete rewrite
you should evaluate carefully your future platform before deciding.

If you have the above strong requirements, you can have a look at the following projects:
  • Plone (nosql, enterprise level, a lot of plugins)
  • Kotti (traditional database storage, more lightweight, easy to approach)
They are both Python based, quite different solutions but they have common roots and a long CMS tradition. They are open source, secure, with a friendly an skilled community and a clean editing experience compared with other "CMS" solutions (you can't call CMS something that looks like a messy version of an admin interface! Just good for technicians or for small projects, not for content editors).

I'm just suggesting: if you are evaluating CMS frameworks, don't choose a solution because it is built with your preferred programming language or framework but consider also other existing solutions. Don't choose a project because you were able to change the logo and few colours quickly. You should evaluate the main available solutions and after that choose the best fit for you... and be prepared to change technology if needed.

Change attitude also means continuously searching for something of better, find new opportunities, learning something of new, learn new development pratices, get involved in other open source communities: it is definitively a good thing. You are not disrupting your existing knowledge, you are improving your experience and enlarging your knowledge. So don't be scared, choose the best for you and be open minded!

Another hint: don't be tempted to write from scratch a new CMS unless you are know well what you are doing and/or you have a good budget with dozens of experienced developers. Still having the idea of writing your new CMS from scratch?! Have a look at how many contributors and how many years are needed before an open source CMS it is considered stable with a good feature set and then decide. Don't reinvent the wheel!

Or if you don't want to learn another framework or programming language but you found the best fit for you: hire a consultant but always choose the best.


PS: if you like adventure and you chose a RDBMS based solution like Kotti you have another option: you can follow a hybrid approach.

This way you can use Kotti as a private content management area and implement your public website with the technology or frontend tools you like exposing data marked as published on the database. There are a lot of benefits due to backend decoupled from the frontend.

Maybe I'll talk about a similar successful case history built with this technique in an another blog post. Stay tuned with @davidemoro.

Update 20150720 - hybrid approach