24 May 2013
Planet Plone
Andreas Jung: Organizing your project life, surviving projects...
This is a short and unsorted collection of personal wisdoms that may help you improving your day and life as a software developer, freelancer, project manager or whatever.
You first, projects second
The first think that counts is you . You and your personal health should have the highest priority. Don't ruin yourself for whatever reason. Your health is your capital.
Don't be reachable at any time
Whatever position you have in a project: you don't have to be reachable at any time for any person. Give your working day a structure. Consider fixed working hours that you do not exceed.
Avoid overtime
Overtime is a bad thing. Yes, things must be done at some point but constant overtime is bad for your health and mood - unless you are a coding maniac.
Don't be a slave of your email client
Reduce to poll time of your email client to one hour or so - being interrupted while programming is a bad thing.
Delay email replies
There are email client add-ons like SendItlater that allow you to answer to an email directly but defer the delivery to a some time in the future. This may slow down email ping-pong between and your customers significantly.
Have separate email clients
For some projects (with lots of email during the day and night) I use a dedicated email client that I can close at any time. I use my standard email client to keep track of my private email and other project email (where I know that there will be only a few mails per day without a big risk of trouble)
Do not respond to all email the same day
If there is some email coming in the late afternoon and you can already smell the trouble by reading the sender or the subject: keep it closed and read it the other day. Do not ruin your last working hour and the rest of the day with trouble emails.
Smell the stress
It takes some experiences to notice when the project stress turns against you. Stress can have various symptoms and they are very individual. Personally I notice upcoming stress situation through problems with my stomach.
Get out of the stress
This is often easier said than doable in reality. But if often helps taking a break for an hour or two and doing sports. First it reduces my aggression level and gives me a more clear thought on some pending problems. Or if you can: take a day off and do something completely different.
Know your limits
Know yourself! You have to know where your personal limits are and how far you can go. While we are all getting older we have to recognize that we can not handle a workload as when we were ten years younger. It does not mean that we are less efficient and effective but we deal with workloads in a different way.
It is you that counts, it is your health that counts. So in order to avoid a burnout: you first, projects and customers second....
24 May 2013 1:35pm GMT
4teamwork: Construct your Testing Data using the Builder Pattern
Test data generation is always a hot topic when it comes to automated software testing. One of my first assignments at 4teamwork was to help with the testing. In the process I was browsing through the test suites of some big projects they are working on and noticed a lot of similar code related to data creation:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
This is very basic object creation code and I'm sure many Plone developers have written a fair amount of it. While this gets the job done, there is a lot of noise, that we don't need to have in every test.

I decided to use a basic implementation of the Builder Pattern to hide the noise in specific Builder classes and make our tests shorter and more expressive at the same time:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
We can now use our Builder classes inside our test-case.
1 2 3 4 5 |
|
Already a big step forward! We have only defined two Builder classes, and we already notice some duplication among them. Defining a base class gives us a place to store the shared behavior:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Finally we hide the different Builder implementations and their instantiation behind a function. This allows us to change the Builders without touching all the tests that use them:
1 2 3 4 5 6 7 |
|
And the final code inside the test-cases looks like:
1 2 3 4 5 6 7 8 9 |
|
Check out this gist to view our current builders.py module. Let me know what you think and leave a comment.
24 May 2013 8:15am GMT
21 May 2013
Planet Plone
Steve McMahon: Dexterity: It's easier than you think
Dexterity is the new content-type development system built into Plone 4.3. It's also usable with Plone 4.1 and 4.2. Lately I've been working on developing a fairly sophisticated content type with Dexterity. It has fieldsets, smart validation and real vocabularies.
All these features were developed through the web. This meant that I was able to show them to project stakeholders - and even do some light usability testing - before ever turning the project into an add-on package. And, when I did convert the project into a Python package, nothing was lost.
Want more? I'll be teaching a class on Developing with Dexterity, June 3-4 at Plone Symposium Midwest.
If you've touched Dexterity at all, you've realized that you may use the TTW field editor to rapidly create a content type with a full set of fields and behaviors. You may be surprised, though, to learn that it's possible to organize the add/edit form into fieldsets, or to wire in validation and vocabularies, without moving the content type to an add-on package.
The trick is that it's possible to edit the XML representation of the field schema all the way through the TTW development process. XML edits show up immediately in your Dexterity type's field display and you may continue to add, move, delete and edit fields there:

If you've followed Dexterity development, you know that this is not really a trick at all: Dexterity was meant to work this way. Dexterity maintains the TTW field list as an XML representation via the supermodel package, which translates back and forth between field schemas and XML. While you're developing TTW, the editable XML representation is stored in the content type's Factory Type Information.
Documentation on how to add fieldsets, validators, vocabularies and permissions via XML is available in the recently created Dexterity XML Reference. To give you a hint of how it works, it's this easy to do a fieldset:
<schema>
...
<fieldset name="test"
label="Test Fieldset"
description="Description of test fieldset">
<field name="three" type="zope.schema.TextLine">
<description/>
<title>Three</title>
</field>
<field name="four" type="zope.schema.TextLine">
<description/>
<title>Four</title>
</field>
</fieldset>
...
</schema>
The Bad News
The gotcha is that editing the XML is currently a ZMI step. Go to portal_types, find the type, edit the XML.
The Good News
This is about to get better. The next minor release of Dexterity will have an "Edit XML Model" on the field editor:

Pushing it will use Plone 4.3's new resource editor package (built on the Ace editor) to open an editor. And, not only can you edit, but on save you'll get XML syntax and Dexterity resource checking:

When you're ready to move your project to a Python package, you may keep the XML model you've developed and continue to elaborate your fieldsets by editing that model.
21 May 2013 6:14pm GMT
Lennart Regebro: p4a.plonecalendar 2.1 released
p4a.plonecalendar is a calendar for Plone. Mainly it is a set of calendaring views whose main feature is that can be used without Javascript.
Version 2.1′s main feature is that it adds Plone 4.3 support.
21 May 2013 4:27pm GMT
Reinout van Rees: Advanced Python through Django: metaclasses - Peter Inglesby
Metaclasses are a handy feature of Python and Django makes good use of them.
When you create certain kinds of classes in Django, a metaclass will do something to the class before it is created. For forms, the various attributes of the class are converted into a base_fields dictionary on the class.
Similarly, a subclass of Model also fires up a metaclass that does some registering. A foreignkey to another model adds a relation back on that other model, for instance.
As a recap, a class is something that can be instantiated into an object. It can have an __init__() method that does something upon instantiation. type(your_instance) will return the class.
Did you know that you can create classes dynamically? See for yourself:
>>> name = 'ExampleClass'
>>> bases = (object,)
>>> attrs = {'__init__': lambda self: print('Hello from __init__')}
>>> ExampleClass = type(name, bases, attrs)
>>> example = ExampleClass()
Hello From __init__
>>> type(example)
<class '__console__.ExampleClass'>
So... we can actually control how classes are created! You could create a create_class() method that calls type but that modifies, for instance, the name. Or we could take all the attributes and add them to a base_fields dictionary on the instance. Hey, that's what we saw in the first Django form example!
Now, what is type exactly? It is a class that creates classes.
This also means we can subclass it! The most useful thing to override in our subclass is the __new__() method. The __init__() method creates instances from the class, the __new__() creates classes. (Update: it is a little bit different, actually, see Venelin's comment below). So again we can modify the name and/or the attributes.
How do you use it in practice? Normally you'd set a __metaclass__ attribute on a class. This tells python to use that metaclass for creating the class. The same for subclasses. This is how our Django form classes use the metaclass specified in Django's base Form class.
Django uses metaclasses in five places: admin media, models, forms, formfields, form widgets. Grep for metaclass in your local django source code once to get a better feel for how Django uses it.
Note on python 3: it uses a slightly different syntax for specifying metaclasses. So Django 1.5 uses six to support both ways in a single codebase.
Warning: don't overuse metaclasses. They can make code difficult to debug and follow. Use Django as a good example of how to use metaclasses. Django saves you a lot of work by using metaclasses in a few locations.
See https://github.com/inglesp/Metaclasses
Nice way of giving a presentation, btw. Some sort of semi-interactive python prompt. The software is online at https://github.com/inglesp/prescons
21 May 2013 6:38am GMT
Reinout van Rees: The imaginative programmer - Zed Shaw
His goal: teach programmers to be more creative.
He's got a love/hate relationship with creativity. The first part of his talk was impossible to summarize. You'll have to watch the video later on :-)
- Artists tell him he's not artistic because he works on developing technical skills.
- Guitarists tell him he's not a real guitarist as he doesn't play in a band. And 'cause he builds his own guitars he's a programmer, not a Real Guitarist.
- Writers tell him he's not a writer because he writes technical books.
- Programmers tell him he's not a programmer because he doesn't work on their project. And by the way, he's a (technical) writer now, so he's not a programmer.
He's not creative enough. Or so the others say. Or he's not acceptable. How to deal with creativity? In a way, you can re-phrase creativity. Programmers are always making something from nothing, right? Isn't that the pinnacle of creativity?
Here are four hypothetical persons:
- Technique, no imagination: a stereotypical programmer.
- Imagination, no technique: stereotypical biz dude.
- No imagination, no technique. Probably doesn't exist.
- Both imagination and technique. Zed's goal.
Zed's imaginative programmer process. Everyone has a process (if they're good), here's the one he proposes to help you be more creative:
- You start with an idea.
- You establish a concept that helps form the idea. It gives your idea clothes.
- Research techniques or tools. Do some research or you'll pay for it later on.
- Refine the concept through composition. So put a box around the vast world of available possibilities. Just mark which features are inside and outside the concept.
- Explore through prototypes. Throw away code or use paper prototypes for instance. This saves you so much time later.
- You make it real.
We are programmers, so we should iterate this process.
He tried this process with http://projectzorn.com/, going through all the stages. And he's probably going to work on it during the sprints this weekend, so join him if you want.
21 May 2013 6:13am GMT
20 May 2013
Planet Plone
Martijn Faassen: Obviel 1.0!
I'm proud to announce the release of Obviel 1.0:
Obviel is a client-side web framework that supports powerful UI composition based on an easy to learn core. On top of that Obviel adds a lot of features, such as templating, i18n support, form generation and validation, and routing. Obviel stays close to HTML but lets you build sophisticated components when you need to.
Obviel has come a long way since its beginnings. On top of the core we've added a template language, an internationalization system that integrates with JavaScript and templates alike and a routing library. So it's high time for the One Dot Oh release!
Standout Features of Obviel
-
a powerful core that enables model-driven UI composition. If you know jQuery it will be easy to learn this core.
-
Integrated internationalization (i18n) based on gettext. In a world with multiple languages we need UIs that can be easily translated to other languages. I haven't met a client-side web framework yet that can beat Obviel in this area.
Obviel offers an i18n approach that lets you mark strings in your JavaScript code in the gettext style:
_("My translatable string")and also lets you mark translatable strings in templates:
<p data-trans="">My translatable string</p>
Obviel then offers tools to automatically extract these strings into a .pot file that you can offer to translators in various ways; gettext has vary extensive tool support.
See Obviel Template i18n and Internationalizing your Obviel Project for more information.
-
Extensive documentation. Documentation has been and is a priority and Obviel has been documented to bits.
-
Testing is as much a priority as the docs are: Obviel is extensively unit tested using the Buster.JS JavaScript testing framework.
-
Automatic form construction using client-side validation: Obviel Forms
Obviel Forms: http://www.obviel.org/en/1.0/form.html
-
Routing: path (/foo/bar) to object and object to path with Traject.
Traject lets you build a nested navigation space on the client-side. Not only can you route a path to an object, but you can also generate a path for an object, something that results in cleaner and more decoupled code.
What's next for Obviel?
We have been transitioning the code from bitbucket to github and from mercurial to git to make it more accessible to JavaScript hackers who are more familiar with git. We're still busy updating the docs, but the transfer has been complete and the code now lives on github.
We've been doing lots of research on using a JavaScript module system for Obviel so we can better maintain the codebase. I've been overwhelmed by the options, but soon we'll pick one, I promise! We'll also introduce various JavaScript codebase maintenance tools such as the Grunt task runner.
We are still busy working on a configurable transceiver framework for integrating Obviel with a diversity of backends (HTTP, websockets, localstorage): Obviel Sync. More on this soon!
20 May 2013 2:02pm GMT
19 May 2013
Planet Plone
Asko Soukka: Cross-browser test your Plone add-on with Robot Framework, Travis-CI and Sauce Labs
Thanks to Rok Garbas, I became aware of Sauce Labsduring the Plone testing sprint.
Finally, I had some time to try it myself, and I managed to make it work pretty well with Robot Framework and Travis-CI:
I try to start from the very beginning, but if you already have Robot Framework tests, or even Travis-CI-integration, you could just skip these initial steps.
Bootstrap Templer
Create buildout directory for Templer installation:
$ mkdir templer-buildout
$ cd templer-buildout/
Get bootstrap.py:
$ curl -o http://downloads.buildout.org/2/bootstrap.py
Create buildout.cfg:
[buildout]
parts = templer
[templer]
recipe = zc.recipe.egg
eggs =
templer.core
templer.plone
Run bootstrap and buildout to install Templer:
$ python bootstrap.py
$ bin/buildout
Create a new product with Templer
Call the buildout-installed to create a new product with Robot Framework test example:
$ templer-buildout/bin/templer plone_basic example.product
Be careful to answer true for the following question about including Robot test templates:
robot tests (should the default robot test be included) [false]: true
Run buildout:
$ cd example.product
$ python bootstrap.py --distribute
$ bin/buildout
Update Robot Framework tests to be Selenium grid ready
Using Sauce Labs with Robot Framework (Selenium library) is similar to using robot with your own selenium grid. It mainly requires making the browser opening keyword configurable with a few selected variables.
Update src/example/product/tests/robot_test.txt with:
*** Settings ***
Library Selenium2Library timeout=10 implicit_wait=0.5
Suite Setup Start browser
Suite Teardown Close All Browsers
*** Variables ***
${ZOPE_HOST} localhost
${ZOPE_PORT} 55001
${ZOPE_URL} http://${ZOPE_HOST}:${ZOPE_PORT}
${PLONE_SITE_ID} plone
${PLONE_URL} ${ZOPE_URL}/${PLONE_SITE_ID}
${BROWSER} Firefox
${REMOTE_URL}
${DESIRED_CAPABILITIES} platform:Linux
${BUILD_NUMBER} manual
*** Test Cases ***
Plone site
[Tags] start
Go to ${PLONE_URL}
Page should contain Plone site
*** Keywords ***
Start browser
${BUILD_INFO} = Set variable
... build:${BUILD_NUMBER},name:${SUITE_NAME} | ${TEST_NAME}
Open browser ${PLONE_URL} ${BROWSER}
... remote_url=${REMOTE_URL}
... desired_capabilities=${DESIRED_CAPABILITIES},${BUILD_INFO}
Let me explain what all those variables are about:
- ZOPE_HOST should match the host for which ZServer is started during the test setup (ZServer host is configured with ZSERVER_HOST-environment variable. It defaults to localhost.
- ZOPE_PORT should match the port number which ZServer is started to listen during the test setup (ZServer pot is configured with ZSERVER_PORT-environment variable. It defaults to 55001, but we reconfigure it later by environment variables with one of the ports currently supported by Sauce Labs.
- ZOPE_URL is a convenience variable for accessing Zope application root.
- PLONE_SITE_ID is the Plone portal object id (and path name) for the test site. It default to plone, but it can be configured with PLONE_SITE_ID-environment variable. The default should be ok for most cases.
- PLONE_URL is a convenience variable for accessing the Plone site front-page.
- BROWSER selects the browser to run the tests with. The supported values depend on Selenium Python-package and can also be read from the documentation of Open browser-keyword in Selenium2Library keywordsdocumentation.
- REMOTE_URL enables testing with Selenium grid by defining the url of the Selenium hub to use.
- DESIRED_CAPABILITIES is used to pass various extra parameters for Selenium hub (e.g. the browser version to use or test metadata).
- BUILD_NUMBER is used to identify the Travis-CI build on Sauce Labs.
When robot tests for Plone are run using bin/test, all the variables above can be overridden by defining corresponding ROBOT_-prefixed environment variable (e.g. ROBOT_REMOTE_URL).
Add Travis-CI configuration with Sauce Labs -support
There are a few steps in adding Travis-CI-support into your product.
At first, create travis.cfg to do the required magic for minimizing buildout-time and setting a few required environment variables. Thanks to the great community, we can just extend a public template:
[buildout]
extends =
https://raw.github.com/collective/buildout.plonetest/master/travis-4.x.cfg
package-name = example.product
package-extras = [test]
allow-hosts +=
code.google.com
robotframework.googlecode.com
[versions]
plone.app.testing = 4.2.2
[environment]
ZSERVER_PORT= 8080
ROBOT_ZOPE_PORT= 8080
[test]
environment = environment
Create .travis.yml for letting Travis-CI to know how the environment should be set up and the tests run:
---
language: python
python: '2.7'
install:
- mkdir -p buildout-cache/downloads
- python bootstrap.py -c travis.cfg
- bin/buildout -N -t 3 -c travis.cfg
- curl -O http://saucelabs.com/downloads/Sauce-Connect-latest.zip
- unzip Sauce-Connect-latest.zip
- java -jar Sauce-Connect.jar $SAUCE_USERNAME $SAUCE_ACCESS_KEY -i $TRAVIS_JOB_ID
-f CONNECTED &
- JAVA_PID=$!
before_script:
- bash -c "while [ ! -f CONNECTED ]; do sleep 2; done"
script: bin/test
after_script:
- kill $JAVA_PID
env:
global:
- ROBOT_BUILD_NUMBER=travis-$TRAVIS_BUILD_NUMBER
- ROBOT_REMOTE_URL=http://$SAUCE_USERNAME:$SAUCE_ACCESS_KEY@ondemand.saucelabs.com:80/wd/hub
matrix:
- ROBOT_BROWSER=firefox ROBOT_DESIRED_CAPABILITIES=tunnel-identifier:$TRAVIS_JOB_ID
- ROBOT_BROWSER=ie ROBOT_DESIRED_CAPABILITIES=tunnel-identifier:$TRAVIS_JOB_ID
- ROBOT_DESIRED_CAPABILITIES="platform:OS X 10.8,browserName:iPad,version:6,tunnel-identifier:$TRAVIS_JOB_ID"
Let me describe:
- Lines 4-7: Run buildout.
- Lines 8-14: Download and start Sauce Connect.
- Line 15: Run tests.
- Lines 16-17: Shutdown Sauce Connect.
- Lines 18-21: Define required environment variables for letting robot to use Sauce Labs.
- Lines 22-25: Define build matrix for running the tests with Sauce Labs' default Firefox, Internet Explorer and Mobile Safari. tunnel-identifier-stuff is required for Sauce Labs to allow more than one simultaneous tunnels for the same user account.
Next, define your Sauce Labs username and access key as secret, encrypted, environment variables SAUCE_USERNAME and SAUCE_ACCESS_KEY.
Currently, Sauce Labs offers unlimited free subscription with three simultaneous connections (e.g. running tests for three different browsers at the same time) for Open Source projects. Just make sure to register the account for your project, not yourself. Public repository url is required for the creating the account and it cannot be changed afterwards.
-
Install Travis gem for Ruby (and install Ruby before that when required):
$ gem install travis # or sudo gem ...
-
use travis-command to insert encrypted environment variables into the product's .travis.yml:
$ travis encrypt SAUCE_USERNAME=myusername -r mygithubname/example.product --add env.global
$ travis encrypt SAUCE_ACCESS_KEY=myaccesskey -r mygithubname/example.product --add env.global
Make sure to use your own Sauce Labs username and access key, and your product's Github-repository path (with format username/repo).
Finally, enable Travis-CI-tests for you product either at Travis-CI.org or at GitHub.
Done. If I forgot something, I'll update this post.
Behind the basics: Test level status reporting for Sauce Labs
By default, Sauce Labs doesn't really know did the Selenium tests on it pass or fail. To pass that information from our test runner on Travis-CI to Sauce Labs, we need to add some extra code into our test setup.
At first, append the following into the end of src/example/product/testing.py:
import re
import os
import httplib
import base64
try:
import json
assert json # pyflakes
except ImportError:
import simplejson as json
from robot.libraries.BuiltIn import BuiltIn
USERNAME_ACCESS_KEY = re.compile('^(http|https):\/\/([^:]+):([^@]+)@')
class Keywords:
def report_sauce_status(self, status, tags=[], remote_url=''):
job_id = BuiltIn().get_library_instance(
'Selenium2Library')._current_browser().session_id
if USERNAME_ACCESS_KEY.match(remote_url):
username, access_key =\
USERNAME_ACCESS_KEY.findall(remote_url)[0][1:]
else:
username = os.environ.get('SAUCE_USERNAME')
access_key = os.environ.get('SAUCE_ACCESS_KEY')
if not job_id:
return u"No Sauce job id found. Skipping..."
elif not username or not access_key:
return u"No Sauce environment variables found. Skipping..."
token = base64.encodestring('%s:%s' % (username, access_key))[:-1]
body = json.dumps({'passed': status == 'PASS',
'tags': tags})
connection = httplib.HTTPConnection('saucelabs.com')
connection.request('PUT', '/rest/v1/%s/jobs/%s' % (
username, job_id), body,
headers={'Authorization': 'Basic %s' % token}
)
return connection.getresponse().status
This code defines a custom Robot Framework keyword library with a keyword for passing the test status (and other information) back to Sauce Labs.
Next, we update src/example/product/tests/robot_test.txt to store the session id during the setup of every test and send the test result back to Sauce Labs during the teardown of every test:
*** Settings ***
Library Selenium2Library timeout=10 implicit_wait=0.5
Library example.product.testing.Keywords
Test Setup Start browser
Test Teardown Run keywords Report test status Close All Browsers
*** Variables ***
${ZOPE_HOST} = localhost
${ZOPE_PORT} = 55001
${ZOPE_URL} = http://${ZOPE_HOST}:${ZOPE_PORT}
${PLONE_SITE_ID} = plone
${PLONE_URL} = ${ZOPE_URL}/${PLONE_SITE_ID}
${BROWSER} = Firefox
${REMOTE_URL} =
${DESIRED_CAPABILITIES} = platform:Linux
${BUILD_NUMBER} = manual
*** Test Cases ***
Plone site
[Tags] start
Go to ${PLONE_URL}
Page should contain Plone site
*** Keywords ***
Start browser
${BUILD_INFO} = Set variable
... build:${BUILD_NUMBER},name:${SUITE_NAME} | ${TEST_NAME}
Open browser ${PLONE_URL} ${BROWSER}
... remote_url=${REMOTE_URL}
... desired_capabilities=${DESIRED_CAPABILITIES},${BUILD_INFO}
Report test status
Report sauce status ${TEST_STATUS} ${TEST_TAGS} ${REMOTE_URL}
Please, note how we had to replace suite setup and teardown with test setup and teardown) to open a new Selenium session for every test.
This worked for me. I hope it works for you too.
example.product is available at: https://github.com/datakurre/example.product
19 May 2013 6:58am GMT
Asko Soukka: Speed up your Plone add-on tests on Travis CI with the Unified Installer
Many thanks for Héctor Verlarde for encouraging us to try out Travis CI for testing our own Plone add-ons. Also, thanks for Godefroid Chapelle for showing me, how to run Selenium tests on a headless server, e.g. on Travis CI.
As you may already know, the main issue in testing Plone add-ons on Travis CI is its strict 15 minute time limit on running your test suite. And as you may also know, 15 minutes is not much time for our dear buildout to gather all the required dependencies of Plone or plone.app.testing, and still run our test after the buildout.
As expected, neither did I get far without having issues with the time limit. And for some reason, I couldn't get the earlier solutions to work for me. Eventually, I found out a new solution, surprisingly, with the help of Plone Unified Installer.
Because Plone Unified Installer comes in a single downloadable package and includes a complete buildout-cache usable also in a test buildout, I realized, that it could speed up my test buildout a lot, and it did. Yet, with Plone 4.3 shipping with Dexterity, I would expect it to speed it up even more.
Update: The method described here is adopted as part of buildout.plonetest, which includes more generic configuration to work with all Plone-versions.
Enough talk. Here's my setup:
buildout.cfg
[buildout]
extends = http://dist.plone.org/release/4.2.1/versions.cfg
develop = .
parts = test
versions = versions
[test]
recipe = zc.recipe.testrunner
eggs = my_package[test]
Nothing special here. I expect setup.py of the tested package to include complete extras_require={'test': ... } with all the required dependencies for testing.
So, on a local machine, python bootstrap.py, bin/buildout and bin/test combo should run tests for a freshly cloned package repository just as expected.
travis.cfg
[buildout]
extends = buildout.cfg
parts =
download
install
test
eggs-directory = buildout-cache/eggs
download-cache = buildout-cache/downloads
[download]
recipe = hexagonit.recipe.download
url = https://launchpad.net/plone/4.2/4.2.1/+download/Plone-4.2.1-UnifiedInstaller.tgz
[install]
recipe = collective.recipe.cmd
on_install = true
cmds = tar jxvf ${download:location}/Plone-4.2.1-UnifiedInstaller/packages/buildout-cache.tar.bz2 1>/dev/null
Here's the magic for re-using Plone Unified Installer for your test buildout:
- At first, download and unpack the installer in [download] part
- then extract its buildout-cache in [install] part into the locations defined in [buildout] part.
As you might guessed, after this, buildout needs to download only the extra requirements of the tested package! Long live Plone Unified Installer!
.travis.yml
language: python
python: "2.7"
install:
- mkdir -p buildout-cache/downloads
- python bootstrap.py -c travis.cfg
- bin/buildout -N -t 3 -c travis.cfg
script: bin/test
Note, how we need to create a buildout-cache-directory for downloads as defined earlier in travis.cfg. The rest should be easy: we just do the bootstrap and run our tests with sane buildout-options, and... that's all.
.travis.yml for robotsuite
Oh, in the beginning, I mentiond about learning something important from Godefroid. Well, if you have followed me on creating zope.testrunner-compatible Robot Framework -tests with plone.app.testing, you only need to add a few extra lines to make your Robot Framework tests runnable on Travis CI:
language: python
python: "2.7"
install:
- mkdir -p buildout-cache/downloads
- python bootstrap.py -c travis.cfg
- bin/buildout -N -t 3 -c travis.cfg
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
script: bin/test
If you think, this is cool, please, give some love for the Travis CI team!
19 May 2013 6:38am GMT
Asko Soukka: Getting started with Robot Framework and plone.app.testing
Selenium testing Plone doesn't need to be difficult. Actually, with the recent hard work done for robotframework-selenium2libraryit's the easiest way to test your add-ons! (Thanks a lot to these folks!)
I'll show you, how to create your first zope.testrunnercompatible Robot Framework tests for your custom Plone add-on. Also, everything you already know about plone.app.testing, zope.testrunner or Python unittest-library, should apply here.
Update: An up-to-date documentation for writing Robot Framework tests for Plone is available as part of Plone Developer Documentation.
Environment
Here's our dummy Plone add-on package with its testing buildout:
bootstrap.py
buildout.cfg
CHANGES.txt
README.txt
setup.py
src
src/my
src/my_package
src/my_package/__init__.py
src/my_package/tests
src/my_package/tests/__init__.py
src/my_package/tests/test_robot.py
src/my_package/tests/test_accessibility.robot
We've got bootstrap.py, empty text files for README and CHANGES, and the following setup.pyto define our (empty) add-on package:
from setuptools import setup, find_packages
version = "1.0.0"
setup(
name="my-package",
version=version,
description="An example Plone add-on",
long_description=(open("README.txt").read() + "\n" +
open("CHANGES.txt").read()),
# Get more strings from
# http://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
"Programming Language :: Python",
],
keywords="",
author="",
author_email="",
url="",
license="GPL",
packages=find_packages("src", exclude=["ez_setup"]),
package_dir={"": "src"},
include_package_data=True,
zip_safe=False,
install_requires=[
"setuptools",
],
extras_require={"test": [
"plone.app.testing",
"rootsuite",
"robotframework-selenium2library",
]},
entry_points="""
# -*- Entry points: -*-
[z3c.autoinclude.plugin]
target = plone
"""
)
Note, how we've defined test-extras for our package to require robotsuite and robotframework-selenium2librarypackages in addition to the usual plone.app.testing.
And here's our buildout.cfg to set up the test runner:
[buildout]
extends = http://dist.plone.org/release/4.2-latest/versions.cfg
parts = test
develop = .
[test]
recipe = zc.recipe.testrunner
eggs = my-package [test]
Test suite
Let's write our first test suite in Robot Framework syntax into src/my_package/tests/test_accessibility.robot:
*** Settings ***
Library Selenium2Library timeout=10 implicit_wait=0.5
Suite Setup Start browser
Suite Teardown Close All Browsers
*** Test Cases ***
Plone Accessibility
Goto homepage
Click link Accessibility
Page should contain Accessibility Statement
*** Keywords ***
Start browser
Open browser http://localhost:55001/plone/
Goto homepage
Go to http://localhost:55001/plone/
Page should contain Plone site
Note, how we import and configure Selenium2Library, and how we expect Plone to be found at http://localhost:55001/plone/. That's how plone.app.testing serves it.
Robotsuite
The last step is to glue our Robot Framework test suite and plone.app.testing together. That's done with robotsuite-package by defining new a RobotTestSuite with the default PLONE_ZSERVER-layer from plone.app.testing in src/my_package/tests/test_robot.py:
import unittest
import robotsuite
from plone.app.testing import PLONE_ZSERVER
from plone.testing import layered
def test_suite():
suite = unittest.TestSuite()
suite.addTests([
layered(robotsuite.RobotTestSuite("test_accessibility.robot"),
layer=PLONE_ZSERVER),
])
return suite
If you have ever defined a Python doctest test suite to be used with plone.app.testing, the above should look very familiar.
Running
With everything above in place, just run:
-
bootstrap (with a Plone-compatible Python or virtualenv)
$ python bootstrap.py
-
buildout
$ bin/buildout
-
and test
$ bin/test
and you should see something like:
$ python bootstrap.py
Downloading http://pypi.python.org/packages/source/d/distribute/distribute-0.6.35.tar.gz
Extracting in /var/folders/b1/mld_r9wj1jbfwf2jcfl_d61sc6kdnb/T/tmp902seC
Now working in /var/folders/b1/mld_r9wj1jbfwf2jcfl_d61sc6kdnb/T/tmp902seC/distribute-0.6.35
Building a Distribute egg in /var/folders/b1/mld_r9wj1jbfwf2jcfl_d61sc6kdnb/T/tmp69NImk
/var/folders/b1/mld_r9wj1jbfwf2jcfl_d61sc6kdnb/T/tmp69NImk/distribute-0.6.35-py2.7.egg
Creating directory '/.../bin'.
Creating directory '/.../parts'.
Creating directory '/.../develop-eggs'.
Generated script '/.../bin/buildout'.
$ bin/buildout
Develop: '/.../.'
Installing test.
...
Generated script '/.../bin/test'.
$ bin/test
Running plone.app.testing.layers.Plone:ZServer tests:
Set up plone.testing.zca.LayerCleanup in 0.000 seconds.
Set up plone.testing.z2.Startup in 0.398 seconds.
Set up plone.app.testing.layers.PloneFixture in 9.921 seconds.
Set up plone.testing.z2.ZServer in 0.506 seconds.
Set up plone.app.testing.layers.Plone:ZServer in 0.000 seconds.
Ran 1 tests with 0 failures and 0 errors in 2.969 seconds.
Tearing down left over layers:
Tear down plone.app.testing.layers.Plone:ZServer in 0.000 seconds.
Tear down plone.app.testing.layers.PloneFixture in 0.088 seconds.
Tear down plone.testing.z2.ZServer in 5.151 seconds.
Tear down plone.testing.z2.Startup in 0.009 seconds.
Tear down plone.testing.zca.LayerCleanup in 0.005 seconds.
You should also find Robot Framework logs and reports being generated into your buildout directory under parts/test.
Custom layer
Obviously, we'd like to run our test against a Plone with our own add-on installed. That requires a custom test layer, as described at plone.app.testing.
Let's start by adding a few more files:
src/my_package/configure.zcml
src/my_package/hello_world.pt
src/my_package/testing.py
src/my_package/tests/test_hello_world.robot
At first we define our custom view to be tested in src/my_package/configure.zcml:
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<browser:page
name="hello-world"
for="Products.CMFCore.interfaces.ISiteRoot"
template="hello_world.pt"
permission="zope2.View"
/>
</configure>
and in src/my_package/hello_world.pt:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
lang="en"
metal:use-macro="context/main_template/macros/master"
i18n:domain="plone">
<body>
<metal:content-core fill-slot="content-core">
<metal:content-core define-macro="content-core">
<p>Hello World!</p>
</metal:content-core>
</metal:content-core>
</body>
</html>
Then we define our custom test layer in src/my_package/testing.py:
from plone.app.testing import (
PloneSandboxLayer,
FunctionalTesting,
PLONE_FIXTURE,
)
from plone.testing.z2 import ZSERVER_FIXTURE
class MyPackageLayer(PloneSandboxLayer):
defaultBases = (PLONE_FIXTURE,)
def setUpZope(self, app, configurationContext):
import my_package
self.loadZCML(package=my_package)
MY_PACKAGE_FIXTURE = MyPackageLayer()
MY_PACKAGE_ROBOT_TESTING = FunctionalTesting(
bases=(MY_PACKAGE_FIXTURE, ZSERVER_FIXTURE),
name="MyPackage:Robot")
Note, how we build on top of PloneSandboxLayer and how we create our final acceptance test layer by combining our custom MY_PACKAGE_FIXTURE and ZSERVER_FIXTURE. The latter would make our Plone sandbox served at http://localhost:55001/. Finally, FunctionalTesting gives us a clean isolated Plone site to be played with for each test case.
Finally, we write a new Robot Framework test suite into src/my_package/tests/test_hello_world.robot:
*** Settings ***
Library Selenium2Library timeout=10 implicit_wait=0.5
Suite Setup Start browser
Suite Teardown Close All Browsers
*** Test Cases ***
Hello World
Go to http://localhost:55001/plone/hello-world
Page should contain Hello World!
*** Keywords ***
Start browser
Open browser http://localhost:55001/plone/
We can now include our new test suite in src/my_package/tests/test_robot.py:
import unittest
import robotsuite
from my_package.testing import MY_PACKAGE_ROBOT_TESTING
from plone.app.testing import PLONE_ZSERVER
from plone.testing import layered
def test_suite():
suite = unittest.TestSuite()
suite.addTests([
layered(robotsuite.RobotTestSuite("test_accessibility.robot"),
layer=PLONE_ZSERVER),
layered(robotsuite.RobotTestSuite("test_hello_world.robot"),
layer=MY_PACKAGE_ROBOT_TESTING),
])
return suite
and re-run our tests:
$ bin/test --list-tests
Listing my_package.testing.MyPackage:Robot tests:
Hello_World (test_hello_world.robot)
Listing plone.app.testing.layers.Plone:ZServer tests:
Plone_Accessibility (test_accessibility.robot)
$ bin/test
Running my_package.testing.MyPackage:Robot tests:
Set up plone.testing.zca.LayerCleanup in 0.000 seconds.
Set up plone.testing.z2.Startup in 0.219 seconds.
Set up plone.app.testing.layers.PloneFixture in 7.204 seconds.
Set up my_package.testing.MyPackageLayer in 0.028 seconds.
Set up plone.testing.z2.ZServer in 0.503 seconds.
Set up my_package.testing.MyPackage:Robot in 0.000 seconds.
Ran 1 tests with 0 failures and 0 errors in 2.493 seconds.
Running plone.app.testing.layers.Plone:ZServer tests:
Tear down my_package.testing.MyPackage:Robot in 0.000 seconds.
Tear down my_package.testing.MyPackageLayer in 0.002 seconds.
Set up plone.app.testing.layers.Plone:ZServer in 0.000 seconds.
Ran 1 tests with 0 failures and 0 errors in 2.213 seconds.
Tearing down left over layers:
Tear down plone.app.testing.layers.Plone:ZServer in 0.000 seconds.
Tear down plone.app.testing.layers.PloneFixture in 0.091 seconds.
Tear down plone.testing.z2.ZServer in 5.155 seconds.
Tear down plone.testing.z2.Startup in 0.009 seconds.
Tear down plone.testing.zca.LayerCleanup in 0.005 seconds.
Total: 2 tests, 0 failures, 0 errors in 18.305 seconds.
Logging in
plone.app.testing defines a test user for our test site, but how could our Robot Framework test know her login credentials? Well, we have to make our test to ask for the credentials by defining custom Robot Framework test keywords in Python.
Let's add a couple of more files, as in:
src/my_package/testing_keywords.py
src/my_package/tests/test_login.robot
At first, we type our custom Robot Framework keyword library with test keywords for retrieving the test users credentials into src/my_package/testing_keywords.py:
class Keywords(object):
"""Robot Framework keyword library
"""
def get_test_user_name(self):
import plone.app.testing
return plone.app.testing.interfaces.TEST_USER_NAME
def get_test_user_password(self):
import plone.app.testing
return plone.app.testing.interfaces.TEST_USER_PASSWORD
Then, we can write our new login test into src/my_package/tests/test_login.robot:
*** Settings ***
Library Selenium2Library timeout=10 implicit_wait=0.5
Library my_package.testing_keywords.Keywords
Suite Setup Start browser
Suite Teardown Close All Browsers
*** Test Cases ***
Log in
${TEST_USER_NAME} = Get test user name
${TEST_USER_PASSWORD} = Get test user password
Go to http://localhost:55001/plone/login_form
Page should contain element __ac_name
Input text __ac_name ${TEST_USER_NAME}
Input text __ac_password ${TEST_USER_PASSWORD}
Click Button Log in
Page should contain element css=#user-name
*** Keywords ***
Start browser
Open browser http://localhost:55001/plone/
Note, how we can import our custom keyword library right after Selenium2Libary. Also, see how we use our custom keywords to retrieve test user's login credentials into Robot Framework test variables and how we use them later in the test.
We can now include our new test suite in src/my_package/tests/test_robot.py:
import unittest
import robotsuite
from my_package.testing import MY_PACKAGE_ROBOT_TESTING
from plone.app.testing import PLONE_ZSERVER
from plone.testing import layered
def test_suite():
suite = unittest.TestSuite()
suite.addTests([
layered(robotsuite.RobotTestSuite("test_accessibility.robot"),
layer=PLONE_ZSERVER),
layered(robotsuite.RobotTestSuite("test_hello_world.robot"),
layer=MY_PACKAGE_ROBOT_TESTING),
layered(robotsuite.RobotTestSuite("test_login.robot"),
layer=PLONE_ZSERVER),
])
return suite
and re-run our tests:
$ bin/test --list-tests
Listing my_package.testing.MyPackage:Robot tests:
Hello_World (test_hello_world.robot)
Listing plone.app.testing.layers.Plone:ZServer tests:
Plone_Accessibility (test_accessibility.robot)
Log_in (test_login.robot)
$ bin/test
Running my_package.testing.MyPackage:Robot tests:
Set up plone.testing.zca.LayerCleanup in 0.000 seconds.
Set up plone.testing.z2.Startup in 0.217 seconds.
Set up plone.app.testing.layers.PloneFixture in 7.132 seconds.
Set up my_package.testing.MyPackageLayer in 0.026 seconds.
Set up plone.testing.z2.ZServer in 0.503 seconds.
Set up my_package.testing.MyPackage:Robot in 0.000 seconds.
Ran 1 tests with 0 failures and 0 errors in 2.473 seconds.
Running plone.app.testing.layers.Plone:ZServer tests:
Tear down my_package.testing.MyPackage:Robot in 0.000 seconds.
Tear down my_package.testing.MyPackageLayer in 0.002 seconds.
Set up plone.app.testing.layers.Plone:ZServer in 0.000 seconds.
Ran 2 tests with 0 failures and 0 errors in 7.766 seconds.
Tearing down left over layers:
Tear down plone.app.testing.layers.Plone:ZServer in 0.000 seconds.
Tear down plone.app.testing.layers.PloneFixture in 0.088 seconds.
Tear down plone.testing.z2.ZServer in 5.156 seconds.
Tear down plone.testing.z2.Startup in 0.009 seconds.
Tear down plone.testing.zca.LayerCleanup in 0.005 seconds.
Total: 3 tests, 0 failures, 0 errors in 23.765 seconds.
Debugging
There's one catch in debugging your code while running Robot Framework tests. It eats your standard input and output, which prevents you to just import pdb; pdb.set_trace(). Instead, you have to add a few more lines to reclaim your I/O at first, and only then let your debugger in:
import sys
for attr in ('stdin', 'stdout', 'stderr'):
setattr(sys, attr, getattr(sys, '__%s__' % attr))
import pdb; pdb.set_trace()
Resources
- plone.act(Plone keyword library candidate)
- Selenium2Library keywords
- Robot Framework built-in keywords
That's all about it to get started. Have fun!
19 May 2013 6:31am GMT
18 May 2013
Planet Plone
Plumi: Welcome to Plumi 4.5
Plumi 4.5 was soft-launched at the beginning of the year. Now that it's been running smoothly for a while, we'd love to introduce you to all the new features and improvements.
New User Interface
The first thing you'll notice about Plumi 4.5 is the beautiful new skin. We've left the old layout inherited from older versions of Plone behind. Right out of the box you will be pleased to see a shiny new visual theme, with a grid-layout and contemporary styling, just right for a video sharing site.
On the front page of the new Plumi skin you can view all the latest videos that have been uploaded, plus feature a video in the slot on top, ready to play back using mediaelement.js player - an HTML5 player that will work in any modern browser. We're re-worked templates throughout the site, making improvements to UI, with more planned for the future.
Diazo
You can also customise Plumi's visual theme for your own needs, and in Plumi 4.5 it is easier using a new implementation of the Diazo theming engine and plone.app theming. Diazo allows you to apply a theme contained in a static HTML web page to a dynamic website created using any server-side technology. With Diazo, you can take an HTML wireframe created by a web designer and turn it into a theme for Plumi.
Mobile Friendly Adaptive Layout
The site is designed to adapt to different screen sizes, and videos will play back on both Android and iOS devices.
New Video Publishing Form
A new video publishing form makes it even easier for users to upload video to a Plumi site. Just drag'n'drop or click browse to select a video file, and watch it upload in the new progress indicator, while you add metadata to your video.
You can click over to another dynamically loaded page as you upload, where you can categorise the film and add a Creative Commons license.
Subtitling Using Amara
We have integrated Amara (formerly Universal Subtitles) which allows users of your Plumi site to easily add or view subtitles for each video, created or attached to the video using the Amara system. Watch the video above to learn more about how easy it is to use Amara, which is a powerful addition to Plumi in terms of accessibility, and use in multi-lingual websites.
Other Improvements
Other fixes and improvements since our last stable release (Plumi 4.4) include replacing gunicorn with uwsgi, making upload of large files more stable, removing views/downloads from the <iframe>, fixing fullscreen video playback, removal of the obsolete callouts content type, and updating mediaelement.js.
Plumi Roadmap
We are looking forward to a 4.5.1 release that may include some more work on templates, followed by 4.6 in which we plan to integrate videos that are hosted on other sites, and new features designed to enhance the ability to use Plumi for social change impact.
You can read the full list of Plumi features here.
18 May 2013 10:08am GMT
17 May 2013
Planet Plone
4teamwork: TooManyRepositories - Manage your GitHub Subscriptions!
If you are a member of collective organisation on GitHub you know the pain: getting lots of GitHub emails for repositories you don't care about.
The collective organisation on GitHub currently has 909 repositories, the Plone organisation has 228 - together, that's over a thousand repositories. That's a lot of emails!
GitHub changed the watching feature last year, which makes it a little bit better. But still, the problems when participating in hundreds of repositories are not solved for me.
There are various solutions for the problem, like using Gmail filters or clicking through the Watched Repositories view on GitHub - but who wants to unwatch a thousand repositories? Disabling automatically watch is also no option for me - I really want to know what's going on in my employer's organisation and the option cannot be configured per organisation.
That's why I wrote github-watchlist, a small script for mass subscribing and unsubscribing repositories using regular expressions.
The Python script let's you configure your subscriptions with a regular expression pipeline and automatically subscribes or unsubscribes the repositories for you.
My configuration looks like this (short version):
1 2 3 4 5 6 7 8 9 10 11 12 |
|
The list of expressions is applied top-down on most repositories I have access to and it does what you think it does :-)
After installing and configuring the github-watchlist you can simply run the update script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
As the script is idempotent we can run it periodically with a cronjob:
1
|
|
See the github-watchlist readme for more details and have fun with it. Give me some feedback if you use it!
17 May 2013 7:56pm GMT
Reinout van Rees: Principle philosophy - Swift
Principle philosophy: a way to discuss our rules and beliefs that govern our actions. He tells it from his personal experience.
His parents wanted to raise him as a good person. So they thought him good principles (like don't be a quitter, don't steal, etc). This is quite black/white though. We are all more gray/gray.
What about the question "how can I be a good programmer"? Programmers use logic, which sounds black/white again: write tests, don't repeat yourself. Sigh.
Talking about things like this is impossible without Immanuel Kant. He differentiates between reason and instinct. If "be happy" were our life goal, we'd just follow our instincts. So what is reason for, then, apart for doing good? Reason has to do with moral. There are three ways of looking at "doing good":
- Duty. Good things can come from duty. Duty can also lead to non-good things, though. Hm, so this is not it.
- Make a difference between the goal and the outcome. The outcome might be bad even though the goal could be worthy.
- Universal lawfullness. Only do something if you know that everybody thinks it is a good idea.
Does this help with a question like "is testing good"?
Gandhi said that a man is the sum of his actions.
In a sense we are the sum of our experiences. So increase the amount of experience that you have. Either have the experiences yourself, or share them like on this conference. Everything looks different from the trenches: learn from eachother.
Some lessons he learned from a little baseball league experience (where he sucked) as a kid:
- Swing for the fences. Aim for a home run. It allows you take great risks (because you have great goals). It motivates you.
- Set reasonable goals, too. Incremental intermediate goals. Those intermediate goals help you progress.
- You suck... and that's totally OK. You're not good at everything. It gives you a different perspective. And you can still give it your best. Also to that almost-unused old project that you get a bug report for.
Some take-aways:
- Build a strong foundation of principles.
- One size doesn't fit all
- Learn from your experiences and share them.
- Build a great network.
- Ask all the right questions.
17 May 2013 9:23am GMT
16 May 2013
Planet Plone
4teamwork: Our blog about Plone and Python
This blog is about Plone, Python and related topics. It reflects the personal views and opinions of its different authors of 4teamwork. If you have questions or corrections to our articles, you are invited to get in touch with us!
4teamwork is a Plone software company based in Bern, Switzerland, consisting of a young and motivated team of 15 skilled developers and consultants.
We have been around in the Plone community for quite some time: Starting at the very early stage of Plone in 2002 and 2003, we have been witnessing its overwhelming growth and maturation during the past decade. On a side note, we had the privilege of organizing the very first Plone sprint in winter 2003 in Bern - as it turns out, the original website of this historic sprint is still available here. Since then, we have been designing, developing, and maintaining sophisticated web solutions in Plone for many governmental and non profit organizations, like zg.ch (canton of Zug, Switzerland), bern.ch (capital of Switzerland) or amnesty.ch (Amnesty International Switzerland). Furthermore, we help companies setting up their own intranet and/or extranet web service using Plone.
In the past few years, we have started to make our various developments publicly available. All these modules are actively maintained and continuously developed. Feel free to browse (and use) our numerous repositories on github.com/4teamwork. Any feedback (or pull requests ;) is welcome!
IMHO, Plone and Python are still going strong - let's see what the future will hold!
16 May 2013 4:00pm GMT
Reinout van Rees: The web of stuff - Zack Voase
A plane flew over (noisily) at the start of his presentation. He put our work in perspective by saying that that was a 80 ton plane and that we're just building websites :-)
Possibilities
Computers used to take up whole rooms, now you have a smartphone. Big data is really big data now. Moore's lawworks both ways, though, so you have really small computers now. An arduino for instance.
He often makes comparison to the human body. All over our body, sensors give off signals that go into the central nervous system. The brain processes it and gives signals back to muscles if necessary. Sensing, feedback, understanding, reaction.
Stuff can talk to the cloud. Like a sensor in your body talks to your mind, stuff can treat the cloud as a brain. The cloud is what allows small tools to be smart.
Stuff does often need a human to interact with it. Like a smartphone. There's all sorts of people thinking about how to "liberate the computers from their human overlords". Why cannot computers sense and act on their own account?
So how do you bridge the gap betwen sensing and acting of stuff? How do you use Django for it? There's a lot available online about sensing and about acting, but not the communication in between.
The communication medium itself is a bit of a problem. You don't want to have a telephone data contract for every single small piece of stuff. A physical connection isn't always handy either.
His preferred communication medium is Twilio for sending SMSs. The stuff has low memory, so the message length limit is fine.
He showed a demo with a card reader that read his London transport card and sended an SMS to his Django site. The card reader was a combination between an arduino, a 'shield' sms sender and an RFID reader. The django app then submits it to foursquare. (The last part didn't work, probably due to a local foursquare problem, but the django app did have all the data he send from his card reader). Nice.
SUCCESS: after the lightning talks he did it again and now it worked!
Personal development
He had never done any hardware work until four months ago. No compiling for arduino. It sounded a bit scary to him.
It is normal, if you start as a beginner, you're slowly getting better if you keep at something. Then you automatically learn more and thus learn that there's a lot you don't know. That's the dip in the middle. Those are the people we need to keep on board so that they push through to the expert stage.
When you're in the middle, you know how bad you are (or how good you aren't yet). That's the risky phase were people quit.
Likewise documentation. Tutorials are useful for beginners. Reference material is useful for experts. There's not a lot in the middle and you're bound to be a bit frustrated in that stage.
So if you're going to start experimenting with electronics, you're bound to hit a wall, for instance when calculating complex electronic schemas. Push on anyway: the first time you make a phone call with your own device is totally worth it.
Two books he recommends to get you started:
- Getting started with Arduino.
- The art of electronics.
16 May 2013 3:47pm GMT
