TriZPUG logoPlanet TriZPUG

Caktus GroupCaktus Consulting Group Seeks Two Python/Django Web Developers

I’m delighted to announce that Caktus is looking for two Python and/or Django web developers to join our team on a contract or part-time basis, with the potential for full-time work in the future.

Caktus builds custom web applications for local and remote clients using a variety of open-source technologies. We are a small team based in the Chapel Hill/Carrboro area of North Carolina (currently residing in Carrboro Creative Coworking). We believe in face-to-face contact, both with clients and amongst ourselves, and employ agile development techniques that emphasize teamwork and collaboration. We encourage you to meet the team and learn more about what we do.

We’re looking for two experienced Python and/or Django web developers who enjoy working on a team and are excited to work on new projects. We have a preference for local candidates, but will consider all submissions. Your work will involve creating and integrating Django apps, working on existing Django projects, deployment, and database work.

You will be working in Linux (Debian-flavor) production environments with Apache and WSGI. Python and relational database experience is required. Django experience is a (big) plus. HTML/CSS and JavaScript experience are also a must, and jQuery is a plus.

If you’re interested in one of these positions, please send us your resume, some sample Python code that you wrote, and links to any open-source projects you’ve contributed to. We’re looking forward to meeting you!

Joe GregorioGoogle API Client for Python

The Google API Client for Python is a new project to implement a Python client for discovery based APIs, which is currently Moderator, Buzz and Latitude. I had pointed out the existence of the discovery document back in May, and the same caveats still apply, it is very early days and you should expect the format to change. On the other hand, having a discovery document as part of the web service itself greatly simplfies the code; the core code is in apiclient/discovery.py and weighs in at less than 300 lines of code. That's not feature complete by any means, but take a look at samples/cmdline/buzz.py to see how easy it can be to interact with the Buzz APIs.

Caktus GroupCaktus Consulting Group Sponsors DjangoCon 2010

DjangoCon 2010 is just around the corner, and I’m proud to announce that Caktus is sponsoring the conference again this year!

DjangoCon is the annual gathering of software developers who use the open source, Python-based Django web framework. We use the framework every day here at Caktus to create custom web applications and dynamic, content-rich web sites. Additionally, starting this year, we’ve put some of that knowledge to use extending and developing applications for the RapidSMS framework. For more information about why we use Django and think it’s so great, check out our blog post titled Why Caktus Uses Django.

This year, the conference is being held again the week of September 6th in the beautiful city of Portland, Oregon. We’ve grown a little since last year at this time; it looks like 6 Caktus team members—Colin, Alex, Karen, Mark, Mike, and myself—will be attending the conference. We’re positively thrilled to be going again this year and we hope to see you there!

Og MacielRunning On Empty

Running on epty

This post has been sitting in my Drafts folder for a while now, as I wasn’t sure when the right time would be to publish it. It is basically my personal reflection on the last 5 years I have worked doing translations for free and open source software (FOSS) and a few lessons I learned along the way. It is also a rant against those who took my labor for granted. Hopefully this quick summary will help you decide whether you want to continue reading the rest of the post or not.

My adventures in the translation (or localization) world started some time in the middle of 2005. I had just started using Ubuntu as my main distribution and being carried away by the buzz and excitement surrounding this new comer, I started looking for ways to “give back”. Not that I hadn’t tried it before, but to tell you the truth, Ubuntu had back then the only friendly and welcoming community out there that wouldn’t treat you with scorn and arrogance if you were a new user.

Eventually I got to learn about the Ubuntu Brazil team and their effort to translate the desktop applications into the Brazilian Portuguese language. Now, I’ve been living in the United Stated for about 2 decades now and technological terms and jargon in Portuguese had never really entered into my vocabulary. In other words, I had absolutely no idea how to say things like “hard drive“, “File“, “Copy, or anything really in Portuguese. But I was determined to lend a helping hand and proceeded to learn on my own and by asking around.

Now, this is not a post about Ubuntu, so I’ll fast forward a bit to the time I became the coordinator for the Ubuntu Brazilian Translation team and was “in charge” of getting this massive collection of applications translated into Brazilian Portuguese before every single release. It was hard work but at the end of the day it felt great to know that more Brazilians would be able to enjoy GNU/Linux in their native tongue. Heck, under my leadership we delivered several releases of Ubuntu with very high levels of translations and absolutely no thank you from those profiting from out work!

After a couple of years I started to feel pretty good about my background in the software translations world. Filled with the best of intentions and the whole “Ubuntu” philosophy, I approached a few upstream translation teams to offer some help and see if our team could lend them a hand. Oddly enough, most refused my offer which only made me more confused. If they were struggling to get to 100% translations, why would they refuse help from “seasoned translators” such ourselves?

After organizing a few IRC meetings where many didn’t show up, some of the GNOME Brazil guys decided to give me a chance and hear my proposal. In the end we settled on the following plan: We, the “Ubuntu guys” would provide the labor (our team was much bigger than all other teams put together), and the GNOMErs would tell us what to do, how to do it, and tell us to “do it over” if our work did not conform with their standards. If this sounds a bit one sided to you, it’s because it was. There was some unexplained hostility towards us that we could not understand. Some of the members of my team eventually excused themselves, telling me in private how frustrating the whole experience was. “We’re breaking our backs here and they treat us like garbage,” said a disgruntled translator. This was in 2006.

This same type of treatment followed us wherever we went. Always the unprovoked hostility and unwillingness to work together. It wasn’t until around the middle of 2007 that someone finally broke the silence and told me: “You guys got the heart in the right place, but did you know that nothing that you have ever translated for Ubuntu comes back our way?” I didn’t know what to say. “What do you mean?” We’re good guys… the whole World benefits from our work… doesn’t it?”

Turns out I had been mistaken about the benefits of doing translations for a distribution. Turns out also that a lot of upstream translators who are not Ubuntu users (and therefore do not have an account in Launchpad) also have strong feelings against the work being done by the “Ubuntu guys”. But instead of channeling their ill feelings toward the entity that designed the machinery, their anger fell on the translators, peons in the whole scheme of things.

I’m glad to say that I woke up from the stupor that had held me for quite some time in a state of delirium and even fanboyism. Yes, I was an Ubuntu fanboy not too long ago! I too drank from the koolaid and was a major source of free PR and goodwill for Canonical. It was early 2007 when I finally moved on and decided to work directly with the upstream projects, embracing a new world full of opportunities and chances for someone as dedicated as myself.

Boy, was I wrong about certain things! For a long time the stigma of having done translations for a distribution stuck to me, causing many unnecessary discussions and personal attacks from people who I had never met or heard before. Worse of all, the internal interests and political agendas within the smaller groups was very harsh and no matter how many packages I translated or how many hours I spent organizing, teaching, reviewing and translating massive documents, I was never given the acknowledgement by my peers or anyone for that matter. Did you know that GNOME 2.26 was literally translated by two people into Brazilian Portuguese? And that one of them was yours truly?

But I kept going for a long time, choosing to ignore all of these things and focus in the main cause: deliver a completely localized operating system for those who speak Brazilian Portuguese. Through the years I saw coordinators and committers being replaced by people with no background what so ever in translations or even from outside the team! There has always been intrigue and malicious interests in pretty much every community out there, but I had always hoped that one day my hard work would be recognized and aspired to one day become the coordinator for the GNOME Brazilian team. Alas, that day never came.

But I kept going and joined several other teams who received me with open arms. For quite some time I was the sole translator, reviewer and committer for Xfce, LXDE, and Openbox. I even joined the effort to localize MeeGo and make it upstream friendly. Whatever free time I managed to get my hands on was spent either translating, reviewing or committing translations to these projects (and GNOME, off course). Even while juggling a brand new career with a steep learning curve, a second child, moving to a different state and seeing my bank account dwindle down, I still made the time to keep going.

Until I ran out of gas! This morning I have chosen to step down as the coordinator for the LXDE and MeeGo teams and have already passed this position to one of my teammates. I am also stepping down as the administrator of these 2 teams in order to focus on my family and some of my pet projects. I will eventually pass the coordination of the Xfce team as well and will only act as a member of said teams, offering a helping hand every now and then (this already applies to GNOME).

This does not mean that I’m no longer involved with the localization of free and open source software. It only means that I’m now sitting on the backseat and am happy to let someone else drive. It also means that I feel unappreciated and even though the thought that every single GNOME user who runs his/her system in Brazilian Portuguese is doing it because of the fruit of my labor and others makes me feel very proud, the truth is that it does not put food on my table.

I have to finish this post by publicly thanking Margie Foster from the MeeGo project for being the only person who has shown appreciation and gratitude for the work I’ve done! Really, thank you!

Frank WierzbickiLeaving Sauce Labs

My time at Sauce Labs is at an end, and so I am looking for a new opportunity. I had a great time at Sauce Labs where I worked on building a cloud based infrastructure for test automation with Selenium. I have been working in software for more than twelve years, often in a lead role. I am well regarded in the Open Source world, where I have participated in and helped build communities. I have been the Jython project lead for six years. I am a committer on the Python project, and a member of the Python Software Foundation. I have done a wide variety of work in recent history: development and leadership work in Java and Python, from parsing Python source and compiling to Java bytecodes, to coding and administrating distributed cloud based web applications. I am able to do work in any of these areas, on either a full time or consulting/contracting basis. My contact information can be found on my Google profile. My LinkedIn profile is a good summary of my credentials.

Joe Gregoriohg-prompt

Hg-prompt, because the only annoyance of Mercurial Queues is accidentally pulling when you have queued patches applied.

# Prompt stuff
D=$'\e[00m'
PINK=$'\e[01;35m'
GREEN=$'\e[01;32m'
ORANGE=$'\e[01;33m'

hg_ps1() {
hg prompt --angle-brackets "<on ${GREEN}<branch>${D}>\
< at ${GREEN}<bookmark>>${D}${PINK}<status>${D}\
< [${ORANGE}<patches|hide_unapplied>${D}]>" 2> /dev/null
}
      

Og MacielTranslations.xfce.org is 1 year old

Happy Birthday

Received the following email this morning:

Last night our Transifex installation turned 1 year old. I think with
101 users and  4012 submissions in 45 languages it has been quite a
step forward compared to the previous mailing list-based submission
system. For that I'd like to thank all the people involved, most
noticeably Jannis for the initial setup, the Transifex guys for help
and fixing bugs, Og for the appliance we've been running for the last
half year and of course the Translators with all their patience and
effort to make it a success.

Cheers,
The Xfce development team.

This has an extra special meaning for me, not only because I am one of the 101 users contributing translations to the Xfce project, or because I’m a huge supporter of the work the Transifex guys have been doing, but because of their use of the Transifex Appliance!

You see, a while back I needed a “pet” project to use as a learning tool to learn about creating, maintaining and deploying software appliances with the technologies we develop here at work. Transifex was the project that caught my attention, mainly for being a tool for translators and for using Django under the hood.

I’ve been maintaining the Transifex Appliance for quite some time now, all by my lonesome self and putting a lot of my free time. So it feels great to hear that the appliance is being used in a production environment and that it is used by several users!

So, congratulations to the Xfce translators and Nick Schermer for sticking with the appliance and providing tons of great feedback on how to improve it!

Joe GregorioThe End of Stuff

The introduction of a computer into a house or business meant the introduction of more stuff. Computer, monitor, cables, printer, etc. The whole "Paperless Office" thing was a sham, owning a computer meant even more paper than ever was printed and lying around. But recently that trend in our house has started to turn around. We're not actually moving in the other direction yet, but I do see things leveling off. Part of that has been the improvement in technology, for example, Google Docs. The value of the electronic form of the document (collaboration) now exceeds the value of the printed form (ease of reading, off-line access). That got me to thinking of how much stuff I own, besides the printer, that may eventually go away, and it was then that I realized that there's already a bunch of stuff that I will never buy again thanks to owning an Android phone:

  1. Watch
  2. MP3 Player
  3. GPS
  4. Compass
  5. Alarm Clock
  6. Stopwatch
  7. Camera
  8. Calculator
  9. USB Thumb Drive

That list will only grow. For example, I soon expect to add Boarding Passes.

And yes, I know, if you are serious about something then the smartphone version won't do for you. For serious photography people it won't replace their camera. Really into camping and wilderness survival, then I doubt you want the smartphone compass. But for most uses the smartphone version is good enough, and that means less stuff.

Caktus GroupCaktus Consulting Group Welcomes Lead Developer Karen Tracey

I’m delighted to welcome Karey Tracey to our growing team of web developers here at Caktus. Karen is a core developer of the Django web framework and specializes in the development and testing of applications for the web. She is also the author of Django 1.1 Testing and Debugging, published by Packt Publishing in April, 2010.

Caktus is a seasoned team of web developers that creates interactive, content-rich sites and applications with the Django web framework. We put a strong emphasis on best practices, employ an agile method, and also actively participate in the Django development community.

For more information about Caktus and our team, check out our newly updated team page!

Og MacielBook Review: Python 3 Object Oriented Programming

Python 3 Object Oriented Programming

I can’t claim to have looked hard for a Python book on object oriented programming (OOP) but I was immediately attracted to the title of this book. Sure, you can find small tutorials here and there about some specific facet of OOP but I don’t recall ever reading something that covers designing public interfaces using abstraction, encapsulation, etc, etc with good and practical examples! If you have, please drop me a link in the comments.

Python 3 Object Oriented Programming by Dusty Phillips does a very decent job of not only introducing the reader to the terminology and the object oriented paradigm (something that is not too complicated to understand) but also offers a comprehensive step-by-step guide that will take you from theory to a real world project. I’ve always felt that anyone can pick up a book about programming and learn its syntax by heart. But putting it all together and designing something that will actually work is something that you usually learn by reading other people’s code or, if you’re lucky enough, from a mentor.
Overall I felt that the book was well written with a great selection of sample code. Whether you already know how to do object oriented programming for other languages or are new to the whole concept and want to learn everything about it, I definitely recommend this book!

Make sure to check the free chapter (Chapter No.7: Python Object Oriented Shortcuts).

Paul SmithOn Big Government and Corporations

Always keep one eye on the government because it doesn't always act in the public interest. Keep two eyes on the corporations because they only act in the public interest by coincidence.

Paul SmithWhy Google Should Avoid Violating Net Neutrality (As Illustrated with Google Charts API)







Og MacielBack from the Tropics

It’s been a while since I last posted anything new. That’s because I took some time off from work and headed down to my old stomping grounds… Brazil! It had been 5 years since I visited my friends and relatives and since I couldn’t make it to GUADEC and take my family on vacation at the same time, we hoped on a straight flight to Rio de Janeiro from Charlotte‘s international airport.

Meeting Kurt

While waiting for my connection flight, I had the great pleasure of finally meeting in person my good friend KurtKraut, someone who I met online during my ‘buntu days and have kept in touch for the last 5 years. It was great to hang out with him and not have to chat via Skype or IRC! I definitely hope to one day host him here in North Carolina one of these days.

We spent some amazing 8 days (excluding days spent at airports and travelling by car to/from our final destination) enjoying some relatively mild days by the beach, even though it was Winter down there! Every day we’d be invited to eat lunch or dinner at someone’s place and at any given moment my dad’s house where we were staying, would be swarmed by an army of cousins, uncles, aunts and friends who wanted to say hi and meet my kids!

Mine!!!

When we weren’t busy chatting, we were busy eating and drinking! I went overboard this time and eat a lot of everything that got in front of me! One funny thing about going back to the place where you grew up after so long is that you miss silly, little stupid things… such as the bubble gum you used to buy when you’re little… the candy, ice cream, bread, even soda that everyone who’s still living there takes for granted. I must have gained quite a few pounds with all the food, beer and caipirinhas consumed in this trip, but what the heck! I don’t get to visit Brazil very often, so it is worth it.

Now, next year will be the 20th anniversary that my parents came to the USA with 3 teenagers who couldn’t speak a single sentence in English, so my family is planning a big family reunion. Hopefully I will be able to sneak out a bit and get to meet some other friends from the South of Brazil… through the years I’ve received many invitations for dinners and BBQ Brazilian style! And who am I to disappoint my friends?

Paul SmithPaul Smith Disambiguation of the Week: Jul 26, 2010

Bet you didn't know there's a Paul Smith who is not me who is also a movie star. I'll be honest: neither did I, really. But I'm sure you'll recognize Paul L. Smith from such films as Red Sonja, and others. I did my usual round of Paul Smith research, and it turns out that Paul L. Smith is actually really mean. Seriously mean.

Who wouldn't be? Sure, he seems happy enjoying a cocktail as Rabban in David Lynch's Dune, but everybody knows that Baron Harkonen likes Sting better. And check out this scene where Paul L. get swindled by Maverick. I don't want to jump on the Mel Gibson hate-train, but jeeze, what an a-hole.

OK, that stuff's bad, but what was it exactly that turned nice normal Paul L. Smith into sadistic prison guard Paul L. Smith from Midnight Express? Could it have been Wonder Woman? I bullshit you not: he's the main bad guy in an episode of Wonder Woman, right? But the poor guy does not get his ass kicked by Wonder Woman (which might have made the whole thing worth it - why else be the main bad guy on Wonder Woman?), instead he gets thwarted by nerds at a sci-fi convention while Lynda Carter golden-lasso's his henchmen. How exactly is that fair? (BTW: fast-forward to 42:30 or so to see Paul L.'s WTF-face)

No, I think the origin of Paul L.'s meanness is this: rejected, lonely, swindled, socially awkward, and not as good-looking as Sting, Paul L. (as Bluto in Robert Altman's Popeye) lowers his sights and makes a pass at Shelley Duvall's Olive Oyl... and still gets rejected in favor of a squinty guy with a speech impediment.

Harsh.

Check out this revealing moment from the same film. "I'm so mean I had a dream of beating myself up / Broke my nose, broke my hand, I wrestled myself to the ground / and then I choked myself to death / I broke the choke, then woke up / ARRGH!"


That guy is mean.

Paul who?
Paul Lawrence Smith
Paul is a...
Hollywood actor
How to tell us apart:
  • Paul L. is totally mean
  • Paul L. no longer goes by Paul L. He and his wife, Eve, moved to Israel and now call themselves Adam and Aviva Eden. Since her name was already Eve, I have to assume that "Aviva" is somehow even more biblical.
  • Paul L's action figure comes with a bazooka and a big knife, whereas my action figure comes with a coffee mug, nerd glasses and a laptop:




  • Paul L. had a speaking part in David Lynch's Dune with Kyle Maclachlan, while my part as an extra in David Lynch's Blue Velvet (with Kyle Maclachlan) was edited out. I guess it's clear which Paul Smith David Lynch likes better. bitch.
  • Did I mention that Paul L. is mean?

Joe GregorioThe Great Recession, Inflation, and China

There are two things that have been bothering me for a while now. The first is that the only realistic way out of our current situation, barring a Japan-like lost decade, is to inflate our way out of the Great Recession, yet there isn't any movement in that direction.

The other thing that has puzzled me has been the treatment of China as if it were an economic miracle, impervious to any rational market behavior. As a general rule, claims of an "Economic Miracle" should be treated to the same scepticism as perpetual motion machines. There are rumblings, centered on bubble-like real-estate prices, that the China bubble is about to burst.

And that leads me back to puzzle number one, and the idea that maybe the Fed does realize that it has to inflate us out of the Great Recession, but that it will be much easier to do after the wheels have come off the Chinese economy, and not before.

TriZPUG EventsTriZPUG July 2010 Meeting: Accessibility with Python

Gary Bishop, Professor of Computer Science for the University of North Carolina at Chapel Hill develops free software for people with special needs. Gary will talk about the work he and his students are doing to enable people with disabilities. He will briefly cover several Python applications and libraries they have developed and then focus on how they are using Python as the back end of their UNC Open Web project.

Joe GregorioApex Math

Lynne has her Apex Math site up and running. Having done teaching and tutoring for years she has strong opinions on how math is taught in schools today, and how it should be changed to help the students and give them a positive attitude about math. She's now taken that experience and put it into a set curriculum for a whole range of grades and areas, from K-2 to Algebra.

She's put a lot of work into the business so far, not just creating the curriculum, but setting up the site, the affiliate program, and recording videos. Two bigs helpers that have made the process easier have been webfaction for hosting and WordPress for the content management.

Paul SmithGreat Talk on Programming Literacy

In 2007, I had the great fortune of being present at PyCon for Robert Lefkowitz' keynote talk entitled "The Importance of Programming Literacy". Seriously, seriously, seriously: if you spend any part of your personal or professional life thinking about technology, education or politics, you owe it to yourself to check this out:

Find the audio from the talk here, and slides from the presentation can be found here.

Joe GregorioMegadata and NoSQL

Do not get me wrong, I'm thrilled to see some of the ideas that I've talked about finally getting traction in the wider community, and pleased that someone came up with a different name than Megadata, but in looking at many of the discussions it appears that there's way too much focus on the "SQL" part of NoSQL. While breaking away from looking at data merely in a relational manner is a good start, it misses the larger picture, which is that working with Megadata, really large data sets, the nature of the problems and the nature of the solutions markedly changes.

On the simplest of level you have to get beyond N=1 thinking, you can't possibly store all that data on one machine, nor can you hope to process it through one machine. Whatever software you build to house and handle all that data must be an N > 1 endeavor.

But also missing is the idea that there are problems that are simpler to solve, or are only possible to solve, once you have enough data . That brings me back to one of the most exciting annoucements at Google IO, which was the Prediction API; in conjunction with Google Storage for Developers it puts the tools for leveraging Megadata into more hands.

So I'm glad to see NoSQL getting traction, but I'm looking forward to the day when the discussion moves beyond what was left behind, and moves on to what new things we can build going forward.

David RayMocking File Upload in In-browser Integration Tests

Background

For our latest project, we have switched from Selenium Remote Control to Windmill for integration testing.

The switch in web testing framework was made due to some issues we faced with version dependencies of Firefox, Selenium, and the 3rd party test runners we were utilizing. Having to patch Selenium server or maintain customized versions of 3rd party testrunners is not on our short list of things we want to do. In addition, serendipitously, Plone guru davisagli posted a good introduction to Plone and Windmill testing.

Problem

For the most part, authoring tests was a relatively straightfoward affair.  The Windmill test recorder does a decent job of capturing input and dumping it out to python.  We ran into an issue testing a form with a file input field.  This is a well documented security issue with Javascript, as allowing the manipulation of the default file input would allow for some nefarious person to potentially upload any document on an end user’s machine to their site.

We still wanted to mock a file upload for our form. With a little bit of Javascript, and a source file on the machine windmill is running against, it turns out to be quite a bit easier than I anticipated.

Solution

Windmill allows Javascript to be executed against the testing window.  Since one cannot change the default value for a file input, the input type must be changed during the test run.

Default Input Element:

<input id="form-widgets-file" name="form.widgets.file" type="file">

Javascript to execute:

client.execJS(js=u"document.getElementById('form-widgets-file').setAttribute('type','text')")

Newly Rendered Field:

<input id="form-widgets-file" name="form.widgets.file" type="text">

Source File to load:
Now that the input element is of type text, we can modify the default text from our windmill test.

file_path = os.path.join(os.path.dirname(__file__),"upload.txt")
    text = open(file_path)
    content = ''
    for line in text.readlines():
        content += line
client.type(id=u'form-widgets-file', text=content)

And there you have it, the form will now have some mock default content for the file input widget, and be processable.

While it does not fully reproduce the end user experience for uploading files in a form, it does allow us to automate testing for forms with file input fields.

Update

As mentioned in the comments, this solution turns out to be situational, at best.

The form that I was testing utilizes a form processor that calls invokeFactory to create the File object. I suspect that David’s correct in his assertion that this type of hack would not work on generating a File object for standard processes (Add New…File, for example).


Og MacielMore Coffee Noise

Coffee Cup

A while back I wrote about how I first got hooked on coffee and received some really good comments and suggestions for new coffees to try. I was immediately attracted to one coffee in particular: Zoka! Don’t ask me what it was but there was something about the name that tickled my fancy. So I sent their customer service department an email and asked if they would send me a few samples. The very next day I received a reply and the promisse that they would send me a couple of bags. Since I had also received 2 other bags of coffee from friends to try I figured I’d report here how the “coffee experiment” went.

Now, I don’t pretend to be an expert or a connoisseur and my oppinion here is nothing but, well… my own oppinion and is not meant to influence what brand of coffee you should buy. I just enjoy drinking coffee and hope you’ll find this useful.

The Great Coffee Experiment

Zoka‘s coffee arrived at my doorstep a few days later on a Friday afternoon. With names such as “Costa Rica Calle de Copey” and “Tangletown Blend“, the two neatly packed bags of whole beans looked very organic-y. The neat label in the front telling you when that specific bag was put together was a nice touch, almost like someone took their time to hand pick the coffee beans and gently places them into the bag (and it smelled great too!).

I first tried the “Costa Rica Calle de Copey” with its promisse to deliver a rich, fruity flavor. After grinding (espresso) enough coffee for my wife and I and impatiently waiting for the brew, we were both impressed with the strong flavor of melon and hints of lemon! I mean, I usually drink my coffee black with sugar (though I’ve drastically cut down on how much sugar I’m using now) and am not too fond of fruity coffee. Maybe because most of the time fruity coffee is a bit too acidic for me. I must say however that I was not put off by this blend and I can see myself drinking it out on the back porch after dinner.

The next day I decided to try “Tangletown” for breakfast and was very pleased with the experience! Tones of chocolate and caramel seem to balance the acidity for a robust cup of coffee! I’m talking about great smooth flavor with an almost chocolaty ending! Needless to say I am now hooked and will need to find a place to buy my next one!

As I mentioned before I still have 2 more bags of coffee to try and am very much looking forward to trying these 2 Brazilian blends: “Caboclo” and “Café Três Pontas“! Until then, feel free to drop me a line with more suggestions or comments. Also, if you come across a bag of “Tangletown”, don’t hesitate to buy it!

Joe GregorioGData Python Client V3

I just pushed a prototype of what I'd like the next version of the GData Python Client to look like, along with a design document. Please send feedback to the gdata python client library contributors mailing list.

David RayDebian Lenny and Plone 4

Background

Plone 4 requires Python >= 2.6.x. Debian Lenny does not provide packages for Python 2.6.x out of the box. Since we have some other dependencies that require us to use Debian at the moment, we will have to shoehorn Python 2.6.x onto Lenny.

I am not interested in compiling from source. Fortunately, the packages we need are available in Debian sid. We are already on the bleeding edge of deploying production apps in beta software (Plone 4), so we might as well grab some packages from sid to liven things up as well.

Solution

In order to use packages from sid, one must add to /etc/apt/sources.list. Append the following line:

# so we can get latest packages
deb http://ftp.uk.debian.org/debian unstable main

Next, run apt-get update. If you attempt to install python2.6 at the point, you will get the following error:

$ apt-get install python2.6
...
Errors were encountered while processing:
python2.6-minimal
python2.6

A little googling leads to this post, which contains the answer:

$ apt-get install -t testing python-central

Now you can install the packages needed for running Plone4:

$ apt-get install python2.6 python2.6-dev

You’ll likely need setuptools as well:

$ wget http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg#md5=bfa92100bd772d5a213eedd356d64086
$ sudo sh setuptools-0.6c11-py2.6.egg


Og MacielGNOME Board of Directors: First Meeting

First GNOME Board Meeting

Today I attended my very first GNOME Board of Directors meeting. Though I won’t be able to vote on issues until July 1st, it was great to witness how the process works and be able to ask questions and receive answers directly from current and former board members.

I must say that the entire meeting felt very streamlined and ran smoothly, partially because of people like Vincent, Brian, Germán and Paul who seem to be on top of everything and juggling several balls at the same time! Stormy must sleep very well at night knowing she can count on people of this caliber to steer the project.

Emily and Bastien, new members like myself, also made their presence felt by asking questions and getting involved in some topics that were discussed. I asked  a few questions myself and tried to absorb as much as possible, juggling work and the action taking place on Gobbi and IRC.

I feel bad for not being able to attend GUADEC this year as I’ll probably be the only Board member not to be present… but I am looking forward to working with these guys and gals and fill the shoes of those who are departing this year!

Og MacielReview: Django 1.2 E-Commerce

Django 1.2 E-Commerce

Django 1.2 E-Commerce“ starts with a very ambitious goal: design, develop and deploy a functional ecommerce web site for the fictional CranStore.com company. Sounds great, doesn’t it?

I started flipping through the usual introductory pages explaining what Django is and why use it for a project like this. It was all fairly brief which already led me to believe that knowledge of Django’s inner works and basic setup and configuration was required to follow along.

Well, the instructions are not as streamlined as other programming books I’ve read and it could be fairly tricky to follow the examples and logic if you’re not already familiar with how Django works. There are several typos in the example code as well, mostly due to missing spaces between the commands and arguments. Adding to the confusion is the style the author chose to deliver his explanation of specific code changes, displaying snippets of code that will leave the reader wondering what specific file is being discussed.

Now, if none of these things sound scary to you, you’ll be happy to know that the project itself is fairly well designed and worth your time. It was also the first time I saw an example of integrating Django with Google Checkout to set up a “shopping cart” mechanism, and by the time you’re done with the second chapter, you will have a very basic but functional ecommerce web site.

The subsequent chapters were a blur, talking about adding external modules and services to enhance your site’s searching capabilities as well as exposing the data from your “store” via APIs and generating reports with ReportLab. The author also talks about making use of javascript to add that AJAX-y feeling that we’ve come to expect of most modern sites and how to take advantage of S3 storage to sell your product.

The last chapter finally walks you through a few different ways you can deploy your final project to the world out there. I thought it was interesting to see Fabric being mentioned as a driver for deployment, as I have been playing with it at work to help me perform a series of tests on several different hosts for QAing purposes. Come to think of it, this may have been the first time I’ve seen it mentioned in a book, so I’m glad that this project seems to be picking up steam.

Overall, even with the issues of poor proof checking of the source code and the “everything and the kitchen sink” approach to the first chapters, if you’re not new to Django and need to get some ideas on how to design and develop an ecommerce website, you may want to check out this book. I give it 3 out of 5 stars.

Joe GregorioLaunchBox Digital Deadline

The window for applications for LaunchBox Digital closes in 8 days, so if you are in the RTP area and are a startup, or want to launch a startup, get your act together and submit your application. Check out the FAQ for more details.

Joe GregorioGamenclature

Videogame nomenclature seems to be slipping into my kids everyday speach. Two examples:

Reilly was watching a preview for Men in Black and was impressed with the guns:

Woah, how did they get all those cool items?

Later he was playing cards at the kitchen table with his sister:

Pause the game, I'll be right back.

Og MacielWeek in Review: June 14th – June 18th, 2010

Week in Review

Another busy week at work means a quiet week here…

Heck of a week and GNOME Foundation Board of Directors

137 issues resolved and counting!

One important piece of news is that I have been elected to the GNOME Foundation Board of Directors together with other 6 members! Thank you all of you who voted for me! I intent to devote a bigger chunk of my time to be a proactive[...]

Og MacielHeck of a week and GNOME Foundation Board of Directors

It’s been another crazy/hectic week for me at work, so blogging and pretty much all other activities had to take the back seat.

137 issues resolved and counting!

One important piece of news is that I have been elected to the GNOME Foundation Board of Directors together with other 6 members! Thank you all of you who voted for me! I intent to devote a bigger chunk of my time to be a proactive, hands on and very vocal member of this group and will strive to blog about my experience as much as I can!

Next week should be just as crazy as the last 2 but I will try to blog at least once to let people know what’s going on in my neck of the woods!

Josh JohnsonMasquerading As Another User In a Zope 3 Browser View

I had a requirement for Anonymous Users to add content to a designated folder in my Plone site. They submit a form, then the form handling code validates and creates an object. Simple. Or maybe not.

Proxy Roles exist for PythonScripts in Zope 2, but my form was a zope3-style browser view, so that wasn’t an option.

I struggled a lot with this, and after much googling and help from folks on #plone, I came up with this approach, using the AccessControl module that comes with Zope 2.

Here’s what it looks like:

...
from AccessControl.SecurityManagement import newSecurityManager, getSecurityManager, setSecurityManager
from Products.CMFCore.utils import getToolByName
...
class MyViewClass(SomeBaseViewClass):
    # without going into detail here, assume that __init__ is passed a context and request object
    # that are set as instance properties.

    def someProcessorMethod(self):
        # I've created a folder called "Special Folder" at the root of my Plone site. 

        portal = getToolByName(self.context, 'portal_url').getPortalObject() 

        owner = portal['special-folder'].getWrappedOwner()

        # stash the existing security manager so we can restore it
        old_security_manager = getSecurityManager()

        # create a new context, as the owner of the folder
        newSecurityManager(self.request, user)

        try:
            # make the content
            portal['special-folder'].invokeFactory('Document',
                                                   'anonymous-content-ftw',
                                                   title='Anonymous Content FTW!')
        except:
            # we want to ensure that setSecurityManager gets called
            # in reality you should do more here!
            pass

        # restore the original context
        setSecurityManager(old_security_manager)

That’s all there is to it. The nice thing about this approach is that the user who owns the special folder
could change, and the code will still work.

Be careful not to do this without very seriously considering the security rammifications, and be extra careful about
where you allow the view to be used.

For example, if you had used self.context.getWrappedOwner, and the view was mapped to ‘*’, imagine
the mess that could be made if the wrong anonymous user hit the view on every level of your site. :)

Special thanks to Mario Orlandi for this post, which is where I snagged the idea to use getWrappedOwner(). :)

EDIT: After posting this in #plone, petschki pointed out that I should wrap the content creation in a try block to catch exceptions, so I added that to the example code. This way the security manager will be restored even if there’s an exception during content creation.


TriZPUG EventsLos Angeles PyCamp 2010

The UCLA Department of Psychology and the UCLA Graduate School of Education & Information Studies host the Los Angeles PyCamp 2010. For beginners, this ultra-low-cost Python Boot Camp makes you productive so you can get your work done quickly. PyCamp emphasizes the features which make Python a simpler and more efficient language. Following along with example Python PushUps™ speeds your learning process in a modern high-tech classroom. Become a self-sufficient Python developer in just five days at PyCamp! Conducted on the campus of UCLA, PyCamp comes with your own single OS/single developer copy of Wing Professional Python IDE. Read the article for more information.

Og MacielWeek in Review: June 7th – June 11th, 2010

Three more days until my birthday! Want to take a look at my wish list?

It was a very busy week, so I didn’t spend the same amount of time writing as the previous weeks. Thank you for the kind wishes on my birthday!

Also, thank you Conzar, Aigars Mahinovs, Paulo Dias, Tassos Bassoukos and Rodney Dyer for the awesome tips related to playing World of Warcraft on Linux!

Playing World of Warcraft on Linux with Wine

Yes, I’m still alive and kicking. Been really busy at work and haven’t had the time or energy to write anything here. I have however kept my New Year’s resolution of reading a book during lunch break every day! I’m currently reading 2 books at the same time (check what other books I have read and those I have still waiting on my queue in the front page of my blog):

  • For The Win by Cory Doctorow
  • The Fourth Part of the World by Toby Lester

I feel that it is impossible to read Doctorow’s book and not feel the urge to play World of Warcraft (WoW). Impossible! I think the last time I played this game[...]

Joe GregorioDistributed Extensibility

XML namespaces are designed to provide distributed extensibility using URIs.

Distributed extensibility means that multiple people, or organizations, can extend an XML format with out any communication between them, and if they follow the rules they will avoid syntactic collisions. That statement shouldn't be controversial, it's a statement of fact, the definition of distributed extensibility.

The problem is that everyone seems to accept the underlying assumption that distributed extensibilty is a desirable property.

It isn't.

It seems like such a great idea, let a thousand flowers bloom, and all that. And maybe, in a utopian world, where unicorns fart butterflies, it might all work out, but back here the real world, it just falls apart in a bunch of different ways.

The biggest problem with distributed extensibility is that it's a solution to problem that doesn't exist. The idea that you need a system where anyone, anywhere, can add new extension element to an XML document without consulting anyone, at anytime time, is just not a use case. Let's look at Atom as an example; the feedvalidator currently only knows about 80 extension namespaces. You don't need infinite extensiblity to track 80 things. You need a napkin.

But let's put aside the mechanics, what are the social downsides of distributed extensibility?

If you have distributed extensibilty then you don't have to have anyone review the change you are proposing. There's a reason why internally at Google we require that all code get a code review before being checked in; it's important to get another set of eyes on what you're doing. The second downside to distributed extensibility is that there isn't a single place to look for where extensions are defined, which of course presumes they are even documented to begin with.

So what are the alternatives? Fortunately there are several examples of non-distributed extensibility.

Link relations in Atom are tracked in a central repository. Getting your link relation registered is a matter of sending an email.

Another example is HTML5 link relations, in which case you just need to edit a wiki page.

Notice that both of the above systems address the social failings of distributed extensibility by keeping a central repository and providing for reviews of proposed extensions.

If I started today to build a new format I would build it on JSON and not XML; but that's not terribly relevent to the discussion. If I started today to build a format and was forced into using XML, then I would not use namespaces as the extensibility mechanism. Instead I would pick a single namespace, and require extensions to use a registry type system for extensions, like what was done for Atom or HTML5 link relations. If you wanted to add an extension then you'd have to propose the extension, either by email or editing a wiki page, and then that would be added to the registry of all extensions to the format. All extensions would then live in the one namespace for the format. I would also pick a URI for the sole namespace that looked as little like an HTTP URI as possible, maybe use a urn:, or do like WebDAV did and just make up a 4 character string: "DAV:"

And now the caveats. First, this isn't a post about HTML5. I know in the past there was a kerfuffle about distributed extensiblity in HTML5, but I stayed out of it, like I do with almost all discussion of HTML5. Also, this post is just about the concept of distributed extensibilty; I have a whole other tirade about the mechanics of using URIs as the extension mechansim, which will be for another day.

Og MacielPlaying World of Warcraft on Linux with Wine

World of Warcraft

Yes, I’m still alive and kicking. Been really busy at work and haven’t had the time or energy to write anything here. I have however kept my New Year’s resolution of reading a book during lunch break every day! I’m currently reading 2 books at the same time (check what other books I have read and those I have still waiting on my queue in the front page of my blog):

  • For The Win by Cory Doctorow
  • The Fourth Part of the World by Toby Lester

I feel that it is impossible to read Doctorow’s book and not feel the urge to play World of Warcraft (WoW). Impossible! I think the last time I played this game I still lived in Northern New Jersey and was an Ubuntu user (yeah, I’ve matured since then).

So I wanted to play WoW really bad after reading a chapter but wasn’t sure how to do it since I only run GNU/Linux and didn’t feel like setting up a Windows VM just to play a game! Talking to my long time friend Vinny I suddenly realized that I never tried to run the game using Wine, so I decided that once I got home I’d take it for a spin.

After downloading a 3.3MB installer from Blizzard, and installing Wine (sudo conary update wine), I went ahead and ran wine TryWoW.exe. What followed was a series of screens where I simply accepted the defaults and clicked my way through. There were times when a dialog with no messages popped up where all you could do was click on the OK button… so I did.

The installation did require access to the internet and a bundle of approximately 35MB was downloaded in the process. Once the wizard finished I had the option to play the game right there and then! How exciting!

The game takes a few extra seconds to start but eventually I was face to face with the login window. However, I noticed that I had no audio and the video quality lacked a bit. Googling around brought me to these instructions. So I modified my configuration file to include:

SET gxApi “opengl”
SET Sound_SoundOutputSystem “1″
SET Sound_SoundBufferSize “150″
That was it!!! I spent the next 45 minutes playing the game using my trial account and had to be dragged by my wife and kids to the kitchen to eat diner with them!
I’m very satisfied with the experience and extremely pleased with the stability of Wine! Since I have 2 monitors at home, my game window shows up in one monitor while my “normal” desktop is on the other and I have to be careful not to click outside of the game. If I do, then I cannot go back into the game again and have to kill the process and start over.
Well, I still have a few more days until my trial period expires. Will I then update to a full blown account and waste spend my free time investing on my character? To be determined!

Caktus GroupExpanded services, portfolio, and more in the new Caktus web site

We’re pleased to announce the release of the latest and greatest Caktus web presence yet. This edition features an enhanced services section and portfolio. Among other things, the new site demonstrates how our Django-based content management system can be used to connect related pages in customized, innovative ways.

In addition to Django web apps we’ve been building for years here at Caktus, we’re now offering a related service in the mobile health development. Using RapidSMS, a communications framework built on Django, we build applications that add an SMS (text message) component to the standard Django stack. This allows non-standard users, such as clinic and community health workers, to interact with the system. Coupling high-tech and low-tech in this way lets us help remedy communication problems in places where Internet (and even power) are not widely available.

Check out the new site, and please let us know if you have any questions or comments!

Og MacielWeek in Review: May 31st – June 4th, 2010

Three more days until my birthday! Want to take a look at my wish list?

Here’s what happened this week:

Not Going to GUADEC 2010

After several weeks agonizing over how to afford a trip to attend GUADEC 2010, I have finally arrived at the conclusion that I won’t be able to make it. Due to my current financial situation[...]

Emma’s Very Busy Week

I’m the proud father of two voracious young readers! From very early on I was able to instill into my daughters the pleasure of reading books. They also happen to be girly girls, so while most kids ask for toys and video games for their birthdays[...]

Og MacielEmma’s Very Busy Week

I’m the proud father of two voracious young readers! From very early on I was able to instill into my daughters the pleasure of reading books. They also happen to be girly girls, so while most kids ask for toys and video games for their birthdays, mine ask for books and clothes/shoes!

During third grade my oldest daughter happened to pick up “Emma’s very busy week” by Heather Dakota from her school’s library and just couldn’t put it down! I believe that throughout the entire third grade she must have borrowed this book at least 6 times! As a young kid, I remember I could read some books that I really enjoyed over and over, enjoying it every single time as if I were reading it for the first time. She must have gotten this from me.

So now with the Summer break fast approaching she has asked me to buy
her own copy of the book. Again, I usually get all of my books from the public library but those I fall in love with, I just got to have them, so she must have gotten it from me too! I sat down in front of the computer and searched on Amazon, Barnes and NobleBorders, Books on Press, etc, but just could not find a single reference or a way to buy “Emma’s very busy week”.

So I did what everyone does when in doubt and spent some time ‘Googling’ around until I came across Heather Dakota‘s web site. Feeling that I had already exhausted my options, I figured I’d drop her an email and see if she could help us find a place where we could buy the book.

That same day I was pleasantly surprised to receive an email from Heather with a generous offer: she happened to have an extra copy of the book at her house and asked me if I’d mind if she sent it autographed to my daughter! Better yet, she was meeting the illustrator the very next day and said she would also get it autographed!

I profusely thanked her for the offer and decided I would not break the news to my daughter and see how  she would react when she received the package in the mail.

"Emma's very busy week" book

Needless to say, she was in heaven when she received the package yesterday!!! The book was promptly devoured while I took my dog to training class and she’s planning to read it again today!

Thank you Heather for making my daughter’s day! I thank you from the bottom of my heart and we are all looking forward to your next book!

David Rayrst2html and Mercurial

Background

We document. A. Lot.

This is a good thing. No, this is a great thing.  A team member can relatively easily drop-in to someone’s else role/domain based on the exhaustive documentation we have for our policies, procedures, configuration…you get the point.

Up until now, we have been:

This works great, but can be automated to:

  • Reduce the end user actions
  • Reduce the files being managed in SCM

Plan

Looking back at our other hooks, we decided that this would be another ideal use case for a new hook.

Implementation

For the initial version, we analyze the files that have been modified in the change context. If the file extension is rst, we will generate an HTML version of the document and dump it into the directory we are serving out.

Code

def make_html(ui, repo, hooktype, node=None, **kwargs):
    """
    'incoming' hook to create HTML from rst files
    """
    context = repo.changectx(node)

    repo_root = repo.root
    repo_dir = repo_root.split('/')[-1]
    htmldocs_root = '/opt/documentation'
    print 'Creating HTML files and depositing to %s' % (htmldocs_root)

    files = context.files()
    os.chdir(htmldocs_root)
    for file in files:
        filename = file.split('/')[1].split('.')[0]
        fileext = file.split('.')[-1]
        if fileext == 'rst':
            os.system('/usr/bin/rst2html.py %s/%s > %s.html' % (repo_root, file, filename))

Hook Configuration

For each repository that you want this incoming hook to work against, you must edit the .hg/hgrc file to include the following:

[hooks]
 incoming.tag = python:package.name.of.mercurial.hooks:make_html

To Do

  • Add logging for docs that contain poorly formatted ReST
  • Convert hook to generate Sphinx documentation on check  in.

David Ray[Quick Tips] Differentiating Development VMS

We recently acquired new development machines at work (Asus G51J). After bumping up to 8GB of RAM, it was time to start setting up some proper development environments.

Professionally, I’ve never developed on a Windows machine, nor had to use a Windows machine that much.  However, after playing around with the default Windows 7 OS, I welcomed the change from OSX. Is it ‘better’? Not necessarily. But, sometimes change is good, just for the sake of change.

I decided to do all of my development work on virtual machines, using VirtualBox. The latest version of Ubuntu caught my eye, so I’m running with that.

Now, back to the [quick tip] portion of this post…

I’m a visual guy, so I needed a quick and easy way to differentiate VMs that didn’t involve:

  • Remembering which ones were running
  • Reading machine names from the command line

The quickest way, visually, was to differentiate via desktop backgrounds and iconography. For instance, I’m dealing with Plone development daily, and Ruby on Rails development on my own time.  Often, I’ll have both VMs running, just because I can.

I may have more soon, who knows…oh yeah, back to the quick tip….google your framework/language of choice, look for an appropriate image, and slap it onto your desktop as a background image, a la:

There you go, a quick and easy way to differentiate between your VMs.


TriZPUG EventsPenn State Mini-PyCamp 2010

For beginners, this ultra-low-cost Python Boot Camp makes you productive so you can get your work done quickly. PyCamp emphasizes the features which make Python a simpler and more efficient language. Following along by example Python PushUps™ speeds your learning process in a modern high-tech classroom. Become a self-sufficient Python developer in just three days at PyCamp! This mini-PyCamp is a condensed version of the full five day PyCamp and is offered as part of the Plone Symposium East 2010. Read the article for more information.

Joe GregorioGoogle Font API

One of the many cool things launched at Google IO was the Google Font API. I'm now using that and a quick refresh should get you all the content here in a combination of Cantarell and Inconsolata.

I like that fact that typographically my site will render more and more consistently over time.

I love the fact that Google just released 18* open fonts.

* Actually three of the fonts were not just released; the Droid Fonts have been out for a while.

Josh JohnsonOccam’s razor over-applied to virtual networking (or: There’s nothing wrong with Virtual Box anymore)

I’ve been a big proponent of hardware virtualization for a long time. I use it every day in testing, development, and production environments. Today I realized that understanding a problem domain too well can lead a person to overlook simple solutions.

I’m using KVM on my production servers right now (for various reasons and with mixed results), but on the desktop I’ve never been able to really find a well rounded solution I like.

In the past, I used Vmware Server. I stuck with it over a couple of revisions, I was very happy with it. However, I was annoyed/disappointed by the recent change to a web-based, client-server architecture. When I first tried it, it was slow, it was buggy. So I jumped ship.

At that time, VirtualBox had just been bought by Sun, and everything about it was new(ish) and different. I liked how it seemed to be less crash-prone. It had an easier to use UI and was snappier. The guest additions were easier to install.

But then I got to a point where I wanted to do some Plone development. I was running windows as a host OS, and Ubuntu as the guest.

This is where I got stuck. VMware sets up its NAT on a virtual network, so the VMs act like they’re plugged into a virtual router. VirtualBox doesn’t. In Vbox’s case, NAT’tted machines are on a 10.x.x.x network. I believe they can talk to each other, but can’t communicate with the host.

This subtle difference made VirtualBox almost unusable for me. I could set up port forwarding, but there wasn’t a nice UI for it like Vmware had. In fact, it requires a cryptic command line that edits cryptic XML.

I could use bridged networking, which worked OK at home, where I had a wireless router between the VM and the internet, but at work, where we all have static IPs, I had to register the virtual device, and that seemed impractical for a lot of reasons (examples: too many VMs to keep track of, the VMs were no longer sandboxed, etc)

I settled on just setting up port forwarding for port 22 so I could SSH and use SSH tunneling to do any other forwarding I needed. For a 3-client plone site with 3 Apache virtual hosts (SSL, HTTP, and 8080 for the load balancer), that got messy in a hurry. Needless to say I tried to do all of my development on as few VMs as I could.

It was a lot of futzing and difficult work, because, honestly, I ignored the simplest answer.

I just got a new laptop for work, a swank PC to replace an old Mac. For the sake of playing nice, it’s running Windows 7 (yeah, I know). I decided to try VMware again due to the hassles I had with VirtualBox’s networking.

What I wanted was a virtual network that I could connect to a VM through that allowed the VM to get out to the internet. Vmware provided this, VirtualBox did not. (there are other virtualization solutions, I know, but for one reason or another they wouldn’t work for me).

After hours of toil, I realized that Vmware’s NAT doesn’t work in Windows 7 (If you’re on the east coast of the US, you may have heard a faint moan in the distance, that was me screaming into my desk chair when I found that out).

The question I failed to ask before this afternoon was, “Why do they have to the same network?”… you know what? They don’t. Eureka!

So the solution, that I’m frankly a little embarrassed at, is use two network connections. One’s configured as NAT, to provide Internet access and sandboxing, and the other is a Host Only connection, which creates a nice little 192.x.x.x network that you can connect to from the host (but not from outside of the host machine).

Here’s what it looks like (the adapters have to be added while the VM is shut down, or when its initially created):

Interface #1, NAT

Interface #2, the Host-Only Interface

I suppose this is evidence that time wasted is never more valuable than knowledge gained (at least, while you’re wasting time to gain it).


TriZPUG EventsPython Dojo #2

The first Dojo was such a success, we decided to do it again. We are starting earlier this time at 7pm and will be using the trizpug listserv to discuss format and problems to work on.

TriZPUG EventsTriZPUG April 2010 Meeting: RESTful web services + BeautifulSoup

Leonard Richardson, author of the O'Reilly book "RESTful Web Service and developer on Launchpad.net, will be presenting two short talks: "A Spotter's Guide to RESTful Web Services" and "Six Years of BeautifulSoup".

Caktus GroupBasic Django deployment with virtualenv, fabric, pip and rsync

Deployment is usually a tedious process with lots of tinkering until everything is setup just right. We deploy quite a few Django sites on a regular basis here at Caktus and still do tinkering, but we’ve attempted to functionalize some of the core tasks to ease the process. I’ve put together a basic example that outlines local and remote environment setup. This is a simplified example and just one of many ways to deploy a Django project (I learned a lot from Jacob Kaplan-Moss’ django-deployment-workshop), so I encourage you to browse around the Django community to learn more.

The entire source for this example project can be found in the caktus-deployment Bitbucket repository.

Local Development Environment

The project directory is organized like so:

caktus_website/
    __init__.py
    apache/
        staging.conf    -- staging Apache conf
        staging.wsgi    -- staging wsgi file
    blog/
    bootstrap.py        -- bootstrap local environment
    fabfile.py          -- manage remote environments with fabric
    local_settings.py
    manage.py
    media/
    requirements/
        apps.txt        -- pip requirements file
    settings.py
    settings_staging.py -- staging settings file
    urls.py

To setup a local development environment, we’ll create a virtual environment and run bootstrap.py, which is just a simple script that automates installing Python dependencies using pip:

1
2
3
4
5
6
7
8
if "VIRTUAL_ENV" not in os.environ:
    sys.stderr.write("$VIRTUAL_ENV not found.\n\n")
    parser.print_usage()
    sys.exit(-1)
virtualenv = os.environ["VIRTUAL_ENV"]
file_path = os.path.dirname(__file__)
subprocess.call(["pip", "install", "-E", virtualenv, "--requirement",
                 os.path.join(file_path, "requirements/apps.txt")])

bootstrap.py uses requirements/apps.txt (a pip requirements file), so you can source anything off of PyPI as well as mercurial, git, and SVN repositories that include setup.py files. In this example, django’s SVN is the only dependency in apps.txt:

-e svn+http://code.djangoproject.com/svn/django/branches/releases/1.1.X#egg=django

bootstrap.py must be run within virtual environment, so let’s create a new virtualenv (I recommend using virtualenvwrapper) and then run bootstrap.py to install the dependencies:

copelco@montgomery:~/caktus_website$ mkvirtualenv --distribute caktus
(caktus)copelco@montgomery:~/caktus_website$ ./bootstrap.py

Now that our environment is setup (and Django is on the python path), we can run normal Django management commands:

(caktus)copelco@montgomery:~/caktus_website$ ./manage.py syncdb --settings=caktus_website.local_settings
(caktus)copelco@montgomery:~/caktus_website$ ./manage.py runserver --settings=caktus_website.local_settings

Great! That’s it for our local setup, let’s look into deploying the project to a staging server.

Deployment and Remote Management

To help provision the remote server environment (in this case Ubuntu 9.10), we’ll use fabric. fabric allows you to streamline deployment by functionalizing common tasks in Python. I’ve created an example fabfile.py to help bootstrap and deploy the project:

(caktus)copelco@montgomery:~/caktus_website$ fab --list
Available commands:
 
    apache_reload        reload Apache on remote host
    apache_restart       restart Apache on remote host
    bootstrap            initialize remote host environment (virtualenv, dep...
    configtest           test Apache configuration
    create_virtualenv    setup virtualenv on remote host
    deploy               rsync code to remote host
    production           use production environment on remote host
    staging              use staging environment on remote host
    symlink_django       create symbolic link so Apache can serve django adm...
    touch                touch wsgi file to trigger reload
    update_apache_conf   upload apache configuration to remote host
    update_requirements  update external dependencies on remote host

The fabfile splits the deployment process into discrete steps of 1) virtual environment creation, 2) code transfer, and 3) updating the Python dependencies. The bootstrap command wraps everything together, including initial directory creation, so you can setup the server quickly:

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
43
def bootstrap():
    """ initialize remote host environment (virtualenv, deploy, update) """
    require('root', provided_by=('staging', 'production'))
    run('mkdir -p %(root)s' % env)
    run('mkdir -p %s' % os.path.join(env.home, 'www', 'log'))
    create_virtualenv()
    deploy()
    update_requirements()
 
 
def create_virtualenv():
    """ setup virtualenv on remote host """
    require('virtualenv_root', provided_by=('staging', 'production'))
    args = '--clear --distribute'
    run('virtualenv %s %s' % (args, env.virtualenv_root))
 
 
def deploy():
    """ rsync code to remote host """
    require('root', provided_by=('staging', 'production'))
    if env.environment == 'production':
        if not console.confirm('Are you sure you want to deploy production?',
                               default=False):
            utils.abort('Production deployment aborted.')
    extra_opts = '--omit-dir-times'
    rsync_project(
        env.root,
        exclude=RSYNC_EXCLUDE,
        delete=True,
        extra_opts=extra_opts,
    )
    touch()
 
 
def update_requirements():
    """ update external dependencies on remote host """
    require('code_root', provided_by=('staging', 'production'))
    requirements = os.path.join(env.code_root, 'requirements')
    with cd(requirements):
        cmd = ['pip install']
        cmd += ['-E %(virtualenv_root)s' % env]
        cmd += ['--requirement %s' % os.path.join(requirements, 'apps.txt')]
        run(' '.join(cmd))

To bootstrap the staging environment, run:

(caktus)copelco@montgomery:~/caktus_website$ fab staging bootstrap

This will run a few commands over SSH and rsync the project directory to a specific location on the staging server. Using rsync is just one of many ways to transfer code to the server, such as pulling code from a remote repository. The “deploy” fabfile can be modified to perform almost any transfer task. Once the bootstrap process is complete, the directory structure will look like so:

home/
    caktus/
        www/
            staging/
                env/               -- virtual environment
                    bin/
                    include/
                    lib/           -- contains site-packages
                    source/        -- contains django src
                caktus_website/
                    ...
                    apache/
                    manage.py
                    requirements/
                    ...

Now SSH to the server and run syncdb within the newly created virtual environment:

caktus@pike:~/www/staging/caktus_website$ source ../env/bin/activate
(env)caktus@pike:~/www/staging/caktus_website$ ./manage.py syncdb --settings=caktus_website.settings_staging

The staging setting’s file is setup to use sqlite3 to simplify this deployment example. In practice we use PostgreSQL in our production environments, but database setup is for another blog post! To get Apache configured using mod_wsgi, we’ll point the apache configuration to the staging.wsgi file using the WSGIScriptAlias directive. Here’s an example Apache configuration to get a barebones Django environment up and running:

<VirtualHost *:80>
    WSGIScriptReloading On
    WSGIReloadMechanism Process
    WSGIDaemonProcess caktus_website-staging
    WSGIProcessGroup caktus_website-staging
    WSGIApplicationGroup caktus_website-staging
    WSGIPassAuthorization On
 
    WSGIScriptAlias / /home/caktus/www/staging/caktus_website/apache/staging.wsgi/
 
    <Location "/">
        Order Allow,Deny
        Allow from all
    </Location>
 
    <Location "/media">
        SetHandler None
    </Location>
 
    Alias /media /home/caktus/www/staging/caktus_website/media
 
    <Location "/admin-media">
        SetHandler None
    </Location>
 
    Alias /admin-media /home/caktus/www/staging/caktus_website/media/admin
 
    ErrorLog /home/caktus/www/log/error.log
    LogLevel info
    CustomLog /home/caktus/www/log/access.log combined
</VirtualHost>

We’ll use Apache to serve static media (both local and admin media) and direct everything else to the Django instance through mod_wsgi. In order for the wsgi instance to be aware of our environment and project directory, we need to add the virtual environment’s site-packages directory, the project directory to the python path, and tell Django which settings file to use by setting the DJANGO_SETTINGS_MODULE environment variable:

1
2
3
4
5
6
7
8
9
10
11
12
import os
import sys
import site
 
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
site_packages = os.path.join(PROJECT_ROOT, 'env/lib/python2.6/site-packages')
site.addsitedir(os.path.abspath(site_packages))
sys.path.insert(0, PROJECT_ROOT)
os.environ['DJANGO_SETTINGS_MODULE'] = 'caktus_website.settings_staging'
 
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Now just upload the staging apache configuration and reload apache:

(caktus)copelco@montgomery:~/caktus_website$ fab staging update_apache_conf

That’s it! The site should be up and running on your server’s public IP. If you run into any trouble (like a 500 Internal Server Error), just tail the Apache error.log, it’ll usually point you in the right direction.

TriZPUG EventsFirst Python Dojo

The first Triangle community Python Dojo. This is intended to be a forum for community outreach and education and a fun way for advanced python users to brush up on the fundamentals(and communication skills).

TriZPUG EventsPython Hack Night Take Two

Another fun hack night. Bring a personal project to work on or come to help others. If you are new to Python there will be plenty of people there who would love to help you learn. This meeting will be at Cameron Village at the public library room 202A which is on the second floor. http://www.wakegov.com/libraries/locations/cameronvillage/default.htm We only have the room until 8:30 but if people are interested we could head to the Village Draft House afterwards.

David RayOf python eggs and alternate repository links

A quick post/reminder (hopefully for more people than just myself…)

Prior to this position, all of the egg based projects I worked with were eventually released or depended on existing eggs being released at the Cheese Shop.

For eggs that are not hosted at the Cheese Shop, but are dependencies for your egg, you can parametrize the external URLs via dependency_links in setup.py.

Example:

from setuptools import setup, find_packages
import os

version = '1.0'

setup(name='example.package',
         .....
          install_requires=[
             'setuptools',
             'pypi.egg',
             'non-pypi.egg',
          ]
          dependency_links=['http://your.eggs.repository.com'],
          ...
          )

Without the dependency_links url, only the pypi.egg would be downloaded, and the egg would break on installation, as it would not locate the non-pypi.egg.


TriZPUG EventsTriZPUG March 2010 Meeting: Selenium and Sauce

Frank Wierzbicki, lead committer for Jython (http://jython.org/), will demonstrate web systems integration testing with Selenium (http://seleniumhq.org/) and Sauce (http://saucelabs.com/). Selenium is a suite of tools specifically for testing web applications in the browser. Sauce IDE and Remote Client automate Selenium tests "in the cloud" across the ten most popular browsers, providing video of test results. Tests can be recorded from mouse movements and keyboard strokes, or scripted Pythonically. If you develop web applications, you do not want to miss this presentation. As always, lightning talks of ten minutes or less are also welcome. Anything you've learned about Python, no matter how trivial, can be a lightning talk. Mike Revoir hosts at the spacious Duke University North Pavillion (http://trizpug.org/Members/mrevoir/duke_lllh_logistics) where there is plenty of directly adjacent free parking. Read the article for more information.

David RayTag Based Egg Creation with Mercurial Hooks

Background

Our current development infrastructure features a python eggs repository sitting alongside of our mercurial and trac instances on.  The common practice for us is:

  1. Develop and test package(s)
  2. Tag package(s)
  3. Manually generate python eggs for the local repository

As the number of supported projects increases, reducing the number of manual steps in the process is a great benefit, even if we only take advantage of it once every cycle.

Plan

Recently, we added an incoming hook to close tickets in trac based on the mercurial commit changeset log.  Browsing through the list of available hooks, I figured that the same could easily be done for creating eggs on the fly with the tag hook….

R&D

Initial attempts at hooking into the tag trigger had me banging my head against the proverbial brick wall. Despite my best intentions, I could not get the hook to fire at all.  Being relatively new to mercurial (long time subversion user), it took some failed tries (and more Googling) to discover that the repository we are pushing to is never ‘aware’ of a tag hook. Silly n00b….

Implementation

Once I fell back to the appropriate hook, the actual script was relatively straightforward:

def package_tag(ui, repo, hooktype, node=None, **kwargs):
    context = repo.changectx(node)
    log = context.description()
    if 'Added tag' in log:
        repo_root = repo.root
        repo_dir = repo_root.split('/')[-1]
        egg_root = '/opt/eggs'
        tag = log.split(' ')[2]
        print 'Creating egg for Tag %s and depositing to %s' % (tag, egg_root)

        #clone the tag into /tmp
        tmp = '/tmp'
        os.chdir(tmp)
        os.system('hg clone %s' % repo_root)
        os.chdir(repo_dir)
        #build the egg
        os.system('python2.4 setup.py bdist_egg')
        #mv the egg to /opt/eggs
        os.system('mv dist/*.egg %s' % egg_root)
        #delete the /tmp/repo_dir entry
        os.system('rm -rf %s/%s' % (tmp, repo_dir))

Since the mercurial instance contains multiple entries that are not meant to be packaged as eggs, the following snippet is added to .hg/hgrc of each repository we want egg-ified:

    [hooks]
    incoming.tag = python:blitzen.mercurial.hooks:package_tag

Of course, if you want hook to operate on all entries in mercurial, add the snippet to hgweb.config.

The hook is activated anytime a tag is pushed to the remote repository, cloning the repo in /tmp/repo, building the egg, moving it to the eggs repository (/opt/eggs, in our case), and deleting the /tmp/repo entry:

    $ hg tag x.x
    $ hg push
    pushing to http://your.repository.com/repo
    ...
    Creating egg for Tag x.x and depositing to /opt/eggs

Commence time saving!


Kurt GrandisGitosis for Mercurial

As far as DVCSs go I’ve been a git user. That’s mostly because it was the first one I tried and it worked. I’ve been comfy and have enjoyed the world of git and GitHub, but a number of troublemakers have been trying to convince me to give Mercurial a shot. After some nudging I obliged.

After a day or two of toy and experimental projects I started missing one of my primary git utilities–Gitosis. Gitosis is a package that lets you and all your collaborators interact with your git repositories using a single user account over SSH. Gitosis manages user authentication and permissioning using a system of  shared keys without ever exposing actual shell functionality.

It took me a little while to find mercurial-server by LShift, which seems to be Mercurial’s equivalent to Gitosis. So, here is how I got Gitosis-style shared key repository management to work with Mercurial.

Installing Mercurial-Server on Ubuntu 9.10 (Karmic)

Luckily, Paul Crowley of LShift, the author of mercurial-server, has volunteered to manage a Debian package for Mercurial-Server, which makes our lives easier. Thanks!

Install the Mercurial-Server Package

Add the following line to your /etc/apt/sources.list file replacing the url with a mirror that’s appropriate for your location:

deb http://mirrors.kernel.org/ubuntu lucid main universe
then:
$ sudo apt-get update
$ sudo apt-get install mercurial mercurial-server

OR, if you want to install the package manually outside of synaptics or apt you can download the .deb from http://packages.ubuntu.com/lucid/all/mercurial-server/download and then:

$ sudo dpkg -i mercurial-server_1.0.1-1_all.deb

Mercurial-Server should now be installed. Additionally, a new user hg has been created and will be used to manage all your interactions with your mercurial repositories.

Setting Up Mercurial-Server Administrator (root)

You now need to grant yourself administrator rights. All permissioning is done with keys, so you’ll need to copy your public key to mercurial-server’s admin keyring:

$ sudo cp id_rsa.pub /etc/mercurial-server/keys/root/YOURUSERNAME
$ sudo -u hg /usr/share/mercurial-server/refresh-auth

The second command refreshes mercurial-server’s authentication system–authorizing your account as an administrator. You’re good to go!

Managing Mercurial-Server

The hgadmin Repository

Just like gitosis’ gitosis-admin repository, mercurial-server’s functionality can be managed via hgadmin. Go ahead and clone the repo:

$ hg clone ssh://hg@MyMercurialServer/hgadmin

Adding New Users

With your hgadmin repository cloned you can now grant access to new users via their public keys

$ cd hgadmin
$ mkdir -p keys/users/
$ cp ~/kurt-key.pub keys/users/kurt
$ hg add
adding keys/users/kurt
$ hg commit -m "Added Kurt's public key"
$ hg push

You can also allow and organize multiple keys per user. In that scenario you create a directory of keys for each user:

$ cd hgadmin
$ mkdir -p keys/users/kurt
$ cp ~/kurt-home.pub keys/users/kurt/home
$ cp ~/kurt-work.pub keys/users/kurt/work
$ hg add
adding keys/users/kurt/home
adding keys/users/kurt/work
$ hg commit -m "Added keys for Kurt's home and work computers"
$ hg push

Creating New Repositories

As administrator, if you want to create a new repository you simple clone a mercurial project to a path on your mercurial-server. For example:

$ cd my_hg_proj
$ hg clone . ssh://hg@MyMercurialServer/my_hg_project

Now you and your collaborators can clone, push, and pull from the server’s repository just as we did with hgadmin. For example:

$ hg clone ssh://hg@MyMercurialServer/my_hg_project

Managing Repository Permissions

Now that you’ve created your repositories and added users you will want to manage permissions. Repository permissions can be managed through an hgadmin file called access.conf. I recommend reading the mercurial-server documentation for more information on managing security.

So far I’ve found mercurial-server to be a great way to collaborate with others on private repositories outside of Bitbucket. My hat off to Paul Crowley and LShift.

TriZPUG EventsDjango Sprint

We're hosting a Django development sprint at Carrboro Creative Coworking on March 20th and 21st, 2010. A sprint is a concerted, focused period of time in which developers meet in the same space to get things done on a project. This will be a general sprint focused on fixing bugs for the 1.2 release. It doesn't require any previous experience and, if you don't have prior experience contributing to Django, it is the perfect opportunity to start. We'll be there at 9am both days to open the doors. The sprint is being hosted by Caktus Consulting Group. If you need help finding the location or have other questions on the day of the sprint, just give us a call at 919-951-0052.

Caktus GroupCaktus Consulting Group hosts 2nd Django sprint in NC Triangle area

Django is a tool we use every day to build fantastic web apps here at Caktus, and a development sprint is a concerted, focused period of time in which developers meet in the same space to get things done on a project.

We’re proud to annouce that Caktus is hosting another local Django development sprint in the Triangle (Raleigh, Durham, and Chapel Hill/Carrboro) area of North Carolina. The sprint will be held the weekend of March 20th and 21st in Carrboro Creative Coworking, and the purpose of this sprint will be to help push out bug fixes in preparation for the upcoming Django 1.2 release.

If you’re interested in attending, no previous experience contributing to Django is necessary and the sprint will be a great opportunity to start. Work on other open source Django-based projects is welcome too. For more information, check out the corresponding wiki page.

We’ll be there to open the doors at 9am both days. Courtesy of our sponsors there will be free drinks, snacks, and lunch to go around. Hope to see you there!

TriZPUG NewsRegistration Open for Los Angeles PyCamp 2010

For beginners, this ultra-low-cost Python Boot Camp makes you productive so you can get your work done quickly. PyCamp emphasizes the features which make Python a simpler and more efficient language. Following along with example Python PushUps™ speeds your learning process in a modern high-tech classroom. Become a self-sufficient Python developer in just five days at PyCamp! Conducted on the campus of UCLA, PyCamp comes with your own single OS/single developer copy of Wing Professional Python IDE. Read the article for more information.

TriZPUG EventsPython Hack Night The First

Let's get together not just to talk about Python but to use Python. Python Hack Night is where you can get hands-on learning and help on your small projects. If you have a project on which you need some help, then you should come. If you have time to spare and want to help, then you should come. If you just want to come work on a project with other Python hackers, then you should come. If you want to see what projects others are working on, then you should come. Suggestions for more venues to host Python Hack Nights are welcome. Read the article for more information.

Caktus GroupDecoupled Django Apps and the Beauty of Generic Relations

Like just about everyone else, we’ve written our own suite of tools to help with building complex content management systems in Django here at Caktus. We reviewed a number of the existing CMSes out there, but in almost every case the navigation and page structure were so tightly coupled the system broke down when it came time to add additional, non-CMS pages.

We wrote a few little apps, django-pagelets, django-treenav, and django-crumbs, each of which manages different pieces of content (little snippets of content, full CMS pages, navigation, and breadcrumbs). All of the apps are available for free under an open source license on Google Code.

Decoupling was a great move for us, and the ability to plug and play any single part of the system is a huge benefit. Sometimes, however, the completely decoupled architecture was a bit of a pain: If we didn’t provide a link from the pagelets app to the treenav app, how would it be possible to edit a page’s corresponding navigation item on its change form in the Django admin interface?

Enter Generic Relations. Using Django’s content types framework, it’s possible to create admin inlines for generic relations with just a few simple lines of code.

In this case, I’ll show how we allowed users to edit a page’s corresponding navigation item in django-pagelets without requiring everyone (i.e., those who don’t need it) to install django-treenav. First, define the generic inline in the admin.py file of the app that contains the model you want to link to:

from django.contrib.contenttypes import generic
class GenericMenuItemInline(generic.GenericStackedInline):
    """
    Add this inline to your admin class to support editing related menu items
    from that model's admin page.
    """
    max_num = 1
    model = treenav.MenuItem

Then, inside the Admin class for the related model in question, dynamically import and add GenericMenuItemInline to the admin’s list of inlines based on whether or not it’s in the project’s INSTALLED_APPS:

from django.conf import settings
class PageAdmin(admin.ModelAdmin):
    # ...
    inlines = [MyOtherInline]
    if 'treenav' in settings.INSTALLED_APPS:
        from treenav.admin import GenericMenuItemInline
        inlines.insert(0, GenericMenuItemInline)

For more information, see the corresponding pagelets admin.py and treenav admin.py. Thanks for reading and don’t hesitate to post comments if you have any questions!

J. Cliff DyerPsycopg2 has a web site? Sweet!

It just came to my attention that psycopg2, the python driver for PostgreSQL database has a website again! For several months (years?) the site was unavailable, except for an plaintext rant about the author’s ire toward Trac. Now it has several pages of nice-looking sphinx documentation. I haven’t delved into it yet, so I don’t know how good it is, but it’s nice to see a professional looking website providing the public presence for the driver that lets me get at my data. It may be technically irrelevant, but it gives me a little more confidence that the software isn’t as hackish as the site used to be.

If you haven’t seen it yet, I recommend hopping on over to their site, http://initd.org/. It’s well worth a look.

Welcome back psycopg2!


Josh JohnsonGetting the Add… Menu in your custom browser views (content actions)

Background

When I create a new browser view following Professional Plone Development, or using ZopeSkel’s ‘paster addcontent view’ local command, I get (basically) the following code:

Products/MyProduct/browser/myview.py:


from zope.interface import implements, Interface

from Products.Five import BrowserView
from Products.CMFCore.utils import getToolByName

from Products.MyProduct import managementMessageFactory as _

class IMyView(Interface):
    """
    IterationUserstoryAssociation view interface
    """

    def test():
        """ test method"""

class MyView(BrowserView):
    """
    IterationUserstoryAssociation browser view
    """
    implements(IMyView)

    def __init__(self, context, request):
        self.context = context
        self.request = request 

    @property
    def portal_catalog(self):
        return getToolByName(self.context, 'portal_catalog')

    def test():
        """ test method """
        return "OK"

Products/MyProduct/browser/configure.zcml


 <browser:page
      for="*"
      name="myview"
      class=".myview.MyView"
      allowed_interface=".myview.IMyView"
      template="myview_view.pt"
      permission="zope.Public"
      />

Products/MyProduct/browser/myview_view.pt


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      lang="en"
      metal:use-macro="here/main_template/macros/master"
      i18n:domain="Products.MyProduct">
<body>
    <div metal:fill-slot="main">Content Here
    </div>
</body>
</html>

This creates a view on any piece of content in the site, accessible from @@myview. It looks like this (applied to the default Events collection that comes with Plone):

So this is great, and for most views, it’s probably all you need. But sometimes, I’d say most times, you want more from this view. Often we want to segregate our view from Plone, maybe even to the point of using a different slot in the template to toss out most of what main_template does.

But honestly, I think what we usually want is what Plone already has. Every “regular” view of a content object, and its folder_contents view, has certain user interface elements that are usually really handy to have available to your user when they are using your view.

Specifically, I’m talking about the content actions, or the “green bar dropdowns”. Here’s a close up so you know what I’m talking about:

In our view, we don’t get these. That really sucks.

After much toil, I’ve found out why, and two different ways to fix it.

Why is this happening?

First, the why. The “content actions” are actually a viewlet within a dedicated viewlet manager. We can see this through the @@manage-viewlets view:

Along for the ride are the “content views”, which are defined via <action> tags in our Generic Setup profile (the profiles/default/types/*.xml files, specifically). This isn’t confusing at all, is it (and the fact that the viewlet manager and content views viewlet are both named “plone.contentviews” is just icing on the cake!)?

Recall that a viewlet is registered such that it can/will only show up on a content object that implements a specific interface. Another potential limiting facotr, it turns out (my Zope 3 book was in another building today), is the specific view that the viewlet is rendered on. This has lots of potential uses, and speaks to the sweetness of the Component Architecture, but was very hard to figure out.

So the culprit in the case of our content-action-less view, is plone.app.layout. In plone.app.layout.viewlets’ configure.zcml file, lies the following code:


<browser:viewlet
    name="plone.contentactions"
    for="*"
    view="plone.app.layout.globals.interfaces.IViewView"
    manager=".interfaces.IContentViews"
    class=".common.ContentActionsViewlet"
    permission="zope2.View"
    />

<browser:viewlet
    name="plone.contentactions"
    for="*"
    view="plone.app.content.browser.interfaces.IFolderContentsView"
    manager=".interfaces.IContentViews"
    class=".common.ContentActionsViewlet"
    permission="zope2.View"
    />

What this is saying, is that the plone.contentactions viewlet will only show up for content objects that implement plone.app.layout.globals.interfaces.IViewView or plone.app.content.browser.interfaces.IFolderContentsView. This is precisely why we don’t get content actions in our view. Our views aren’t implementing either of those interfaces.

The comment a few lines above these declarations very coyly explains things:


<!-- Content actions (menus)
    The default version is a blank bar; the one with real menus is
    registered for the main view + folder contents only.
-->

So now we get to the two possible solutions. I don’t think one is better than the other, it just depends on how explicit you want to be, and how much you trust plone.app.layout :)

Solution 1: Assign the Content Actions Viewlet Directly to Your Browser View

The first method assigns the viewlet, just as if it was a custom viewlet, to your browser view’s interface. In our case, it would look like this:


<browser:viewlet
    name="plone.contentactions"
    for="*"
    view=".myview.IMyView"
    manager="plone.app.layout.viewlets.interfaces.IContentViews"
    class="plone.app.layout.viewlets.common.ContentActionsViewlet"
    permission="zope2.View"
    />

The advantage here is that the viewlet will render no matter what happens with plone.app.layout. It also gives you more flexibility; you can limit the application of the viewlet in lots of different ways. You could combine the view attribute with the for attribute to limit it to only certain views that are registered to certain content types. You could create a special interface (instead of using the standard issue interface that represents your view class) that could be used as a marker interface to turn the viewlet on or off depending on an arbitrary state of your views. It could get really interesting.

Solution 2: Implement an Already-Registered Interface in Your View Class (This is What You Really Want to Do)

The easiest, and most straight-forward way to do this is to just add one of the interfaces, already registered to the viewlet, to your view class.

plone.app.layout specifies plone.app.layout.globals.interfaces.IViewView and plone.app.content.browser.interfaces.IFolderContentsView. After looking at the interfaces, it becomes obvious that plone.app.layout.globals.interfaces.IViewView is probably what we want to use. Here’s what the code looks like:


from zope.interface import implements, Interface

from Products.Five import BrowserView
from Products.CMFCore.utils import getToolByName

from plone.app.layout.globals.interfaces import IViewView

class IMyView(Interface):
    """
    IterationUserstoryAssociation view interface
    """

    def test():
        """ test method"""

class MyView(BrowserView):
    """
    IterationUserstoryAssociation browser view
    """
    implements(IMyView, IViewView)

    def __init__(self, context, request):
        self.context = context
        self.request = request 

    @property
    def portal_catalog(self):
        return getToolByName(self.context, 'portal_catalog')

    def test():
        """ test method """
        return "OK"

The Final Result

Here you can see it in action:

Wait, theres (probably) another way

Instead of implementing the interface yourself, you may be able to use ZCML to mark your view class with a registered interface… more on that later.

Updates

I mistakenly posted the wrong screen shot in the “The Final Result” section. Fixed 09:00 03/11/2010


Josh JohnsonAdding ZopeSkel to a Buildout

UPDATE I thought this was broken, but I think it was just my convoluted setup. If you try this, please leave a comment and let me know how it went for you!

A quick note, if you want to add zopeskel to your development buildout.

All there is to it is to add the following part to your buildout.cfg:

[zopeskel]
recipe = zc.recipe.egg:scripts

eggs = PasteDeploy
       PasteScript
       ZopeSkel

scripts = zopeskel
          paster

Then just enable it by adding zopeskel to the parts parameter of your main [buildout] section.

[buildout]
     parts = zopeskel

When you re-run bin/buildout, buildout will grab the necessary packages, and create a paster and zopeskel script in your bin directory.

Note: I wanted the paster command, since I’m used to ZopeSkel’s “standard” user interface.  To get this, I had to add the PasteDeploy egg and paster script to the configuration. Feel free to omit it if you just want to use the new “kinder, gentler” interface. I haven’t tried it yet, but I believe the explicit inclusion of the PasteScript egg is unnecessary.


Chris ChurchTriangle MLS Tech Fair

Nine More Minutes will be attending the Triangle MLS Tech Fair as an exhibitor this Thursday, March 11, in Cary, NC.  The tech fair runs from 9:00am to 4:00pm at 111 Realtors Way, Cary, NC.

We’d love it if you could stop by our booth (either #23 or #22 depending on the diagram you’re looking at) and say “hi”.  We have plenty of candy and pens to give away, and would be happy to discuss how our software development and IT consulting services could benefit your small business!

Footnotes