[16:58] <jono> dpm about set?
[16:58] <dpm> jono, ready to roll
[16:58] <jono> you rock :)
[16:59] <dpm> #community rocks!
[16:59] <jono> :)
[17:00] <dpm> hello everybody!
[17:01] <dpm> Welcome to today's first session of Ubuntu Opportunistic Developer Week
[17:02] <dpm> let's just wait a couple of minutes, to see that everyone gets here...
[17:03] <dpm> I should also remind you that today is a snippets day
[17:03] <dpm> of which you'll find all details here: https://wiki.ubuntu.com/PythonSnippets
[17:04] <dpm> There'll also be a snippets party in #ubuntu-app-devel later, so be sure to join the fun!
[17:04] <dpm> Anyway, without further ado...
[17:04] <dpm> [SLIDE 1]
[17:05] <dpm> Welcome to this session on Hot rodding your application for translations support
[17:06] <dpm> In the next hour we'll talk on how to get your app ready to speak a multitude of languages
[17:06] <dpm> and set up so that our awesome translation teams can do their work
[17:06] <dpm> For those who are not using Lernid, here's a direct link to the slides in this session: http://people.ubuntu.com/~dpm/Quickly-i18n.pdf
[17:07] <dpm> This talk will be based on quickly as the framework to opportunistically create your application in no time
[17:08] <dpm> parts of the talk were contributed by didrocks, Didier Roche, who's the main quickly developer
[17:08] <dpm> Let's start having a quick look at the main players involved in the internationalization game:
[17:09] <dpm> [SLIDE 2]
[17:09] <dpm> == GNU Gettext ==
[17:09] <dpm> Gettext is the underlying and most widely used technology to enable translations of Open Source projects.
[17:09] <dpm> It defines a standard format of translation files translators can do their work with (PO files)
[17:09] <dpm> and lets applications load those translations compiled in a binary format (MO files) at runtime.
[17:10] <dpm> It has implementations for many programming languages, and amongst them, of course, Python.
[17:10] <dpm> You'll find that the comprehensive gettext manual at http://www.gnu.org/software/gettext/manual/gettext.html can be a very useful reference,
[17:10] <dpm> The Python implementation of the gettext API is what we'll use to internationalize our project with Quickly today.
[17:11] <dpm> Needless to say, it also comes with some nifty documentation at http://docs.python.org/library/gettext.html
[17:11] <dpm> == intltool ==
[17:11] <dpm> Intltool is a higher level tool that adds functionality to gettext by allowing the extraction of translatable strings from a variety of file formats
[17:11] <dpm> It has also become a standard tool when implementing internationalization for OSS projects. Nearly all (if not all) GNOME projects, for example, use intltool.
[17:12] <dpm> == python-distutils-extra ==
[17:12] <dpm> Python-distutils-extra is a python package that makes it easy to integrate themable icons, documentation and gettext based translations in your python install and build tools, and it's basically an enhancement to python-distutils.
[17:12] <dpm> The project's page is at http://www.glatzor.de/projects/python-distutils-extra/
[17:12] <dpm> The three above technologies (gettext, intltool, python-distutils-extra) are transparently used by quickly, so we won't get into much more detail for now.
[17:13] <dpm> There are also more aspects involved in internationalizing applications, such as font rendering, input methods, etc., but this should get you started for now.
[17:13] <dpm> == Quickly ==
[17:14] <dpm> I'll be very brief here and let you figure out more on quickly as we go along
[17:14] <dpm> For now, it will suffice give you a teaser and tell you that it is the tool which brings back the fun in writing applications!
[17:14] <dpm> == Launchpad Translations ==
[17:15] <dpm> Launchpad Translations ( https://translations.launchpad.net/ ) is the collaborative online tool which allows translation communities to be brought together and translate applications online through its web UI.
[17:15] <dpm> Apart from the very polished UI to provide translations, it has other nice features such as message sharing across project series (translate one message in a series and it instantly propagates to all other shared series),
[17:15] <dpm> global suggestions (suggestions of translations across _all_ projects in Launchpad), automatic imports of translations and automatic commits to bzr branches, several levels of permissions, and a huge translator base.
[17:16] <dpm> On the right hand side of the URL I gave you you can see that there are quite a lot of projects using Launchpad to make translations easy both for developers and translators.
[17:16] <dpm> Ok, enough theory, let's have a go at using quickly to create your first internationalized application
[17:17] <dpm> You can install Quickly on Karmic or Lucid simply by executing 'sudo apt-get install quickly'
[17:18] <dpm> or if you are brave, you can try the trunk version (bzr branch lp:quickly)
[17:18] <dpm> let's focus on the stable version, though
[17:19] <dpm> [SLIDE 3]
[17:19] <dpm> You should see an overview of quickly here
[17:20] <dpm> Quickly has two parts: the core, which basically parses your input and templates.
[17:20] <dpm> Templates are sets of commands and code generators that are designed to work together in an end to end fashion to help developers write a certain kind of application.
[17:21] <dpm> with templates, you can then create application or document set.
[17:21] <dpm> We'll focus there only on i18n with the first template that Quickly 0.2 provides: ubuntu-project (renamed ubuntu-application on the coming 0.4 release!)
[17:21] <dpm> (this template is using Glade, couchdb, has some nice trick for gedit, use bzr, and complete integration with LaunchPad and debian packaging)
[17:22] <dpm> For instance, Lernid that some of you may be using, was created with the ubuntu-project template. (http://www.jonobacon.org/?p=2258 for a shot of the story)
[17:22] <dpm> [SLIDE 4]
[17:22] <dpm> So, let's create first a simple ubuntu-project (assuming you are using Quickly 0.2, the stable version):
[17:22] <dpm> You can run this:
[17:22] <dpm>     quickly create ubuntu-project fooby
[17:23] <dpm> this tells Quickly to use the ubuntu-project template, and to call what is created "fooby"
[17:23] <dpm> This causes a bunch of info to be dumped to the command line, but ends with the application being run
[17:23] <dpm> What Quickly did was to copy over basically a sample application, and do some text switcheroos to customize the app
[17:23] <dpm> You can see there the ui which contains some text that needs translation.
[17:23] <dpm> To start making change to your app, cd to it (normally,
[17:24] <dpm>     cd fooby
[17:24] <dpm> You can then edit your code with $ quickly edit, change the UI with $ quickly glade, and try your changes with $ quickly run
[17:24] <dpm> You can save your change with $ quickly save
[17:24] <dpm> changes
[17:25] <dpm> Finally, to package, share, release your apps so that other will be, with the following commands (not all are necessary): $ quickly package / $ quickly share / $ quickly release
[17:25] <dpm> I won't cover in any more detail Quickly or the ubuntu-project template here (quickly help <command> does this for you),
[17:26] <dpm> you can find more info at: https://wiki.ubuntu.com/MeetingLogs/devweek0909/QuicklyFun
[17:26] <dpm> Let's see what you can do in "quickly edit" and "quickly glade": adding internalization support to your app
[17:26] <dpm> As the project stands now, it has the infrastructure for internationalization in place, but we have to initialize it to enable it.
[17:27] <dpm> This will include:
[17:27] <dpm>  * Initializing gettext
[17:27] <dpm>  * Marking strings for translation
[17:27] <dpm>  * Updating the translation template
[17:28] <dpm> [SLIDE 5]
[17:28] <dpm> First of all, we'll initialize gettext, which will basically be adding four lines of code. Here's how it goes:
[17:28] <dpm>     quickly edit
[17:28] <dpm> This will open all your project files in a text editor (Gedit by default)
[17:28] <dpm> 1. Go to the fooby file and add the following two lines below 'import gtk', near the top of the file:
[17:28] <dpm>     import gettext
[17:28] <dpm>     import locale
[17:29] <dpm> This will import the required modules for internationalization
[17:29] <dpm> 2. Still on the fooby file, add the following line below the 'import logging, optparse' one, near the end of the file:
[17:29] <dpm>     gettext.install('fooby', unicode=True)
[17:29] <dpm> This will install the _() function to mark (and call) translations as such in Python's builtins namespace, based on the 'fooby' domain. The domain basically tells gettext where to load translations from.
[17:30] <dpm> This will also save you to include 'import gettext' statements in all of your project files using gettext. This will do for your first application
[17:30] <dpm> Refer to the gettext documentation to find out more about translation domains.
[17:30] <dpm> 3. Finally, add the following line to 'fooby', before the 'builder = gtk.Builder()' line
[17:30] <dpm>     locale.textdomain('fooby')
[17:30] <dpm> This will tell GtkBuilder about the translation domain as well
[17:31] <dpm> So that was it! Let's move on to marking strings for translation:
[17:31] <dpm> First of all we'll tackle the .destop file
[17:31] <dpm> Open the fooby.desktop.in file and prepend the Name and comment fields with an underscore (_), so they look like:
[17:31] <dpm>     _Name=Fooby
[17:31] <dpm>     _Comment=Fooby application
[17:32] <dpm> This will tell intltool that this strings contain translations
[17:32] <dpm> Next comes the UI. Let's see how you can mark strings in the UI for translation. Try:
[17:32] <dpm>     quickly glade
[17:32] <dpm> This will open your UI files in the glade editor.
[17:32] <dpm> Once opened, click on the "Your application has been created! ..." label, find it in the General > Label field on the right, click on the ellipsis (the three dots) button and...
[17:33] <dpm> amaze at the fact that it has already been marked as "Translatable", so you won't have to do anything.
[17:33] <dpm> Right, so next comes something very important that you'll have to bear in mind for all strings you'd like to be translatable in your application:
[17:33] <dpm>  * using the _() function call.
[17:33] <dpm> This will mark them as translatable and call gettext to load the translations, and should be used for all messages you'd like to present to users.
[17:34] <dpm> Let's just see how we can do this.
[17:34] <dpm> Go back to your fooby file and find the "parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="Show debug messages")" line near the bottom.
[17:34] <dpm> We want the "Show debug messages" message to get shown to users in their language, so we'll enclose it with the _() function, and it will look like:
[17:34] <dpm>     parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help=_("Show debug messages"))
[17:35] <dpm> Now we're done
[17:35] <dpm> The last part will be to update the translations template.
[17:35] <dpm> A translations template is a formatted text file generally named yourproject.pot
[17:35] <dpm> which contains your project's translatable strings in English and is what translators use as a basis for their translations.
[17:36] <dpm> You should do this at least before each release, so that translations are put in this template and are up-to-date for translators to work on.
[17:36] <dpm> It is considered good practice to announce a string freeze (that is, the period in which strings are considered to be stable) a week or two before the release, so that translators know when they can start their work.
[17:36] <dpm> This can be done in several ways with quickly, let's pick one:
[17:36] <dpm>     quickly package
[17:37] <dpm> After running this, you'll notice that (apart from having your application packaged!) there is a 'po' folder containing the translation template, ready for translators to work on.
[17:37] <dpm> If you open it, you'll notice the format and will see that all the strings you marked for translation are there.
[17:37] <dpm> You can also do this with 'quickly share', 'quickly release' or directly using the python-distutils-extra command: './setup.py build_i18n'
[17:37] <dpm> == Launchpad Translations ==
[17:38] <dpm> If this weren't awesome enough, once you've created a project in Launchpad ('quickly share', 'quickly release' or https://help.launchpad.net/ will help you on that) you can expose it for the world to translate
[17:38] <dpm> so that you as a developer can use the automatic bzr import/export features to basically "forget" about translations and translators can use the web UI to translate.
[17:39] <dpm> Let me tell you a bit more on those:
[17:39] <dpm> [SLIDE 6]
[17:39] <dpm> == Automatic imports ==
[17:39] <dpm> Enabling this feature will allow you to automatically import the translation template for your application into Launchpad upon commit, with no further steps required.
[17:39] <dpm> So the basic workflow will be: hack, hack, hack, update template, commit, have translators automagically see the new strings in Launchpad.
[17:40] <dpm> You can find more about this at http://blog.launchpad.net/translations/import-translation-templates-from-your-projects-bazaar-branches and http://blog.launchpad.net/general/trying-out-launchpad-translations
[17:40] <dpm> or at http://blog.launchpad.net/translations/screencast-importing-translation-templates-from-a-bazaar-branch
[17:40] <dpm> == Automatic exports ==
[17:41] <dpm> With automatic exports, you'll be able to complete the whole circle for automation: getting translations committed automatically (daily) to a bzr branch of your choice, so that neither you nor translators have to worry to get translations into your project.
[17:41] <dpm> I personally find this one of the most coolest features
[17:41] <dpm> Here's more info: http://blog.launchpad.net/general/exporting-translations-to-a-bazaar-branch
[17:41] <dpm> And here's a screencast on how to enable it http://blog.launchpad.net/translations/screencast-exporting-translations-to-a-bazaar-branch
[17:42] <dpm> == Permissions ==
[17:42] <dpm> One very important aspect is how you want translations permissions for your project to be. This basically means choosing who will be responsible for submitting and reviewing those
[17:42] <dpm> translations for each language.
[17:42] <dpm> Launchpad is flexible in allowing different levels of openness for translating your project.
[17:43] <dpm> This generally means that you as a maintainer will have to make a decision to balance openness (open translations for everyone) with quality control (a more closed process with reviewers and a QA workflow).
[17:43] <dpm> The Launchpad help page on permissions at https://help.launchpad.net/Translations/YourProject/PermissionPolicies explains very well the different permissions you can use (Open, Structured, Restricted and Closed).
[17:43] <dpm> If you decide for quality, you'll next have to choose to whom you assign the translation of your project.
[17:43] <dpm> Here is where translation groups come to the rescue.
[17:44] <dpm> Translation groups are confederations of translation teams, one for each language you can assign as a pack to translate your project.
[17:44] <dpm> The teams in those groups are considered to be trusted to have experience with translations and generally have a review process in place.
[17:44] <dpm> Here's a list of all current translation groups: https://translations.launchpad.net/+groups
[17:44] <dpm> You can see that the two biggest ones are Launchpad Translators and Ubuntu Translators.
[17:45] <dpm> While you can create a translation group specific to your project, we generally encourage maintainers to choose one of the existing ones,
[17:45] <dpm> in order to reuse the pool of translators and not to further fragment translations communities.
[17:45] <dpm> I personally recommend choosing Restricted (or Structured), assigned to the trusted Launchpad Translators or Ubuntu Translators (if your project is Ubuntu-specific) translations groups
[17:45] <dpm> [SLIDE 7]
[17:46] <dpm> I'll rapidly go through quickly's incoming features and then we can do some Q&A
[17:46] <dpm> Quickly 0.4 will bring a lot of new experiences and commodities to the users (more than 200 commits, 6 months of hard work!) and will be delivered in Lucid.
[17:47] <dpm> Regarding internationalization, all the tedious job of importing/initalizing gettext and adding _() will be done for you in all newly created apps.
[17:47] <dpm> "$ quickly add pythonfile" will also add one boiler plate file containing that for you.
[17:47] <dpm> Quickly 0.6 later on will try to achieve the automatic imports and exports previously described on each $ quickly share / $ quickly release command.
[17:48] <dpm> So, normally, you won't have to bother anymore about localization and being in sync with the awesome work of your contributors
[17:48] <dpm> just mark strings with _()
[17:48] <dpm> So that was it!
[17:48] <dpm> Questions?
 QUESTION: How does one get the translation files for each language from the .pot file?
[17:51] <dpm> That's usually the work of translators
[17:51] <dpm> when you've committed the .pot file to your bzr branch, and it is exposed in Launchpad with automatic imports
[17:52] <dpm> translators will see the translatable strings in Launchpad and start doing their work
[17:53] <dpm> if you've got automatic exports activated, the PO files will be created for you whenever there is a new translation, and committed to your branch of choice
[17:53] <dpm> So, in short, as a maintainer this will happen automagically for you :)
[17:54] <dpm> keep them coming :)
[17:55] <dpm> O I see, gnunerz is asking:
[17:55] <dpm> QUESTION: I get that... I'm just curious as to how does the manual process goes :)
[17:56] <dpm> if you were not using Launchpad, you'd announce that there is a new POT file available, and translators would fetch it, create a PO file containing the translation for their language, and would send it back to you
[17:56] <dpm> The same process: translators always take care of translations, but with a bit more manual work for all people involved
[17:57] <dpm> So, in shourt, I'd recommend using Launchpad and automatic import/export
 QUESTION: It is possible to define which languages I want my app be translated to?
[17:58] <dpm> No, in general you want your application to be available in as many languages as possible, and Launchpad allows translating in almost any language
[17:58] <dpm> You might be able to limit which translations are build in your project's build infrastructure
[17:59] <dpm> But you'll have to explicitly set it up to use just some of the translations
 QUESTION: Does this process also take care of locale stuff, like how is the date presented to the users?
[17:59] <dpm> in general, yes
[18:00] <dpm> but we'd need another session to go into the details :)
[18:00] <dpm> basically, the app must set up the locale settings right on initialization
[18:01] <jono> :)
[18:01] <jono> alrighty
[18:01] <jono> thanks dpm
[18:01] <jono> isn't that man such a freaking rock star?!
[18:01] <jono> everyone needs to give him a hug in #ubuntu-classroom-chat :)
[18:01]  * jono hugs dpm
[18:01] <jono> hi everyone and welcome to the python snippets session at Ubuntu Opportunistic Developer Week!
[18:02] <jono> how are we all doing today?
[18:02] <jono> the focus of this session is some work I have been doing recently around building a library of python snippets and (a) how this library can be useful for you as an opportunistic developer, but also (b) how you contribute to it to make it an even better resource!
[18:03] <jono> so, let's get started
[18:03] <jono> I have always been the kind of person who learns via examples
[18:03] <jono> when I started learning the guitar, I learned by watching other guitarists play, and when I started learning Python and how to build apps on Ubuntu, I have always learned by hunting out little source code examples that do what I need to do and then learning from them and merging them into my programs
[18:04] <jono> the problem is that these snippets were scattered all over the Internet and sometimes pretty hard to find
[18:04] <jono> my dream was to have a program that would bring these snippets together into a library so that I could select them, run them and learn from them
[18:05] <jono> well, on a flight home from England at Christmas, armed with those small bags of peanuts and a few gin and tonics, I decided to write this little program and it is called Acire, named after my wife's name backwards (Erica)
[18:05] <jono> Acire is a really simple program that provides an interface to this library of snippets
[18:06] <jono> let's look at how it works
[18:06] <jono> check out http://farm5.static.flickr.com/4045/4406908674_2934c4d5c0_o.jpg
[18:06] <jono> this is a screenshot of the main Acire interface
[18:06] <jono> in the top-left part of the window there is a drop-down combo box that lists a series of categories of different snippets
[18:07] <jono> when you select a category, the list of snippets that are in that category are listed below
[18:07] <jono> in the screenshot you can see the list of snippets that are in the Python Core category: that is, snippets that demonstrate features in the main Python language
[18:07] <jono> to see a snippet you just click on it and it appears in the code view to the right, all nicely syntax highlighted so you can read it easily :-)
[18:08] <jono> running the snippet is simple, just click on the Execute button
 how come i don't have python core in my acire ?
[18:09] <jono> we had a few out of date python-snippets packages - you might have an old package
[18:09] <jono> embedded in the window is a little terminal view: this is important for snippets that don't have a GUI (such as the Python Core snippets) - if you select a GUI snippet the window will appear when you click the Execute button
[18:09] <jono> running the snippet gives you a good chance to play with it and see how it works and then take a look at the snippet code in the window
[18:10] <jono> another feature is that you can edit the snippet code and when you hit Execute it will run your modified program too: this makes it really easy to play with the snippet inside Acire itself - you can then click the Save As button and save the code somewhere else if you like
[18:10] <jono> we already have a bunch of snippets in Acire: 104 right now (as you can see in the status bar)
[18:11] <jono> here is the current list of categories
[18:11] <jono> http://farm5.static.flickr.com/4050/4406908744_d75cbac80f_o.jpg
[18:11] <jono> if you are curious what my wallpaper is, it is the most awesome duck ever - http://www.flickr.com/photos/w9ned/3563985252/sizes/l/in/pool-1058695 :-)
[18:12] <jono> anyway, back to the screenshot: http://farm5.static.flickr.com/4050/4406908744_d75cbac80f_o.jpg
[18:12] <jono> as you can see, it is pretty cool: it provides a really nice resource for looking at a bunch of python examples and it helps you to learn quickly and easily and solve problems right away
[18:13] <jono> let me now explain how to get it
[18:13] <jono> I have deliberately split the actual python snippets from the graphical interface - this was because many people may want to produce viewers for the snippets (e.g. a KDE version, a web interface etc) so I did not want to depend on the GUI
[18:13] <jono> as such, we have two projects:
[18:14] <jono> acire - the graphical interface to the snippets available at http://www.launchpad.net/acire
[18:14] <jono> python-snippets - the library of snippets available at http://www.launchpad.net/python-snippets
[18:14] <jono> the first thing we want to grab are the snippets
[18:15] <jono> part of my goal here is to make sure that the library of snippets is regularly updated as more snippets are made available
 how can i get the latest version of acire?
[18:15] <jono> I will explain in just a moment :)
[18:15] <jono> fortunately, we have an awesome technology for doing this - Personal Package Archives (PPA) - a place in which you can subscribe to a package and you get regular updates
 is acire going to be available in Lucid?
[18:16] <jono> it runs on Lucid now :)
[18:16] <jono> so, we have a PPA that generates a daily package of the latest python-snippets library
[18:17] <jono> ryanprior, nope, what was it?
[18:17] <jono>  QUESTION: can we add snippets in languages other than Python?
[18:17] <jono> no, Acire and python-snippets is focused on Python
[18:18] <jono> although I would love to see other languages have a similar project :)
[18:18] <jono> so, we have a PPA that generates a daily package of the latest python-snippets library
[18:18] <jono> adding the PPA is simple, just click Applications -> Accessories -> Terminal and add these commands:
[18:18] <jono> sudo add-apt-repository ppa:python-snippets-drivers/python-snippets-daily
[18:18] <jono> sudo apt-get update
[18:18] <jono> sudo apt-get install python-snippets
[18:19] <jono> this will add the snippets to /usr/share/python-snippets
[18:19] <jono> you now need to install Acire to view them
[18:19] <jono> we also have a PPA for this too
[18:20] <jono> I recently kicked out a new release, but I haven't had a chance to provide a Karmic package yet, so the new release is just in Lucid right now - the PPA still has the older release though, so this still works
[18:20] <jono> just follow these steps:
[18:20] <jono> click Applications -> Accessories -> Terminal (or use the Terminal in Lernid!) and add these commands:
[18:20] <jono> sudo add-apt-repository ppa:acire-team/acire-releases
[18:20] <jono> sudo apt-get update
[18:20] <jono> sudo apt-get install acire
[18:21] <jono> all of the instructions for doing this are on https://wiki.ubuntu.com/PythonSnippets
[18:21] <jono> ok, so let's now get to the question about running the latest bleeding edge Acire
[18:21] <jono> some of you may want to grab the latest code for Acire and run it - this is also really simple, just follow these commands:
[18:22] <jono> click Applications -> Accessories -> Terminal (or use the Terminal in Lernid!) and add these commands:
[18:22] <jono> first install all the packages requires to run it:
[18:22] <jono> sudo apt-get install bzr python-desktopcouch-records python-gconf python-gtk2 python-gtksourceview2 python-vte quickly
[18:22] <jono> this will grab everything you need
[18:22] <jono> it may take a little while to grab everything, but not too long :)
 :'( no amd64
[18:23] <jono> yeah, but the 32-bit version should run I imagine
[18:23] <jono> or you can follow these instructions
[18:23] <jono> ok
[18:23] <jono> first install all the packages requires to run it:
[18:23] <jono> sudo apt-get install bzr python-desktopcouch-records python-gconf python-gtk2 python-gtksourceview2 python-vte quickly
[18:23] <jono> next, let's grab the code
[18:23] <jono> again, this is really simple thanks our pal, bzr:
[18:23] <jono> just type in:
[18:23] <jono> bzr branch lp:acire
[18:24] <jono> this will grab the latest acire code from Launchpad
[18:24] <jono> when it has got the code, now enter the directory:
[18:24] <jono> cd acire
[18:24] <jono> and then run it:
[18:24] <jono> quickly run
 A few broken dependencies in Karmic :(
[18:25] <jono> yeah we had a few issues with dependencies, but you can solve them by making sure you run this line:
[18:25] <jono> sudo apt-get install bzr python-desktopcouch-records python-gconf python-gtk2 python-gtksourceview2 python-vte quickly
[18:25] <jono> that will get everything you need
[18:25] <jono> and you obviously need to ensure the python-snippets PPA is installed, as I described above
[18:25] <jono> :)
[18:26] <jono> this will then get you up and running :)
[18:26] <jono> awesome to see you folks getting it up and running :)
[18:26] <jono> now, today is an exciting day as we are really keen to encourage you folks to join us in making a bunch of python snippets today to add to the library
[18:27] <jono> this resource is only as useful as the snippets inside it, so I am really keen to crowdsource this and have any many people as possible join in and contribute snippets
[18:27] <jono> right now we have 104 snippets
[18:27] <jono> my dream for today is that we hit the 150 mark :)
[18:27] <jono> you folks interested in helping?
[18:27] <jono> interesting in helping to make this rock?
[18:27] <jono> :)
[18:27] <jono> we welcome snippets on *any* python module
[18:28] <jono> so if you can do *something* in python, you could write a snippet
[18:28] <jono> whether it is as simple as doing something to a list or using a module such as feedparser
 QUESTION: should snippets for a given package (like PyGTK for example) live in python-snippets, or in pythin-gtk2-doc, or where?
[18:29] <jono> great question ryanprior
[18:29] <jono> let me explain how the snippets are organized
[18:30] <jono> ok
[18:30] <jono> take a look at http://bazaar.launchpad.net/~jonobacon/python-snippets/trunk/files
[18:30] <jono> this is a list of the content in the main python-snippets archive right now
[18:30] <jono> as you can see, there are a bunch of directories
[18:31] <jono> each directory refers to a particular python module
[18:31] <jono> as an example, the gstreamer dir has snippets that use the GStreamer multimedia framework
 This seems like a great opportunity for upstream involvement. We can help people with their documentation.
[18:32] <jono> exactly! :)
[18:32] <jono> inside each dir lives the snippets
[18:32] <jono> so if we click on the gwibber dir:
[18:32] <jono> http://bazaar.launchpad.net/~jonobacon/python-snippets/trunk/files/head:/gwibber/
[18:32] <jono> there is one snippet
[18:33] <jono> gwibber is a python module that ships in Lucid that allows you to microblog right from your app
[18:33] <jono> so the snippet we have is sendmessage.py
[18:33] <jono> you can see it at http://bazaar.launchpad.net/~jonobacon/python-snippets/trunk/annotate/head:/gwibber/sendmessage.py
[18:33] <jono> and that explains how in just a few lines of Python you can tweet, dent, Facebook etc
[18:34] <jono> so in a nutshell the library of snippets is in /usr/share/python-snippets and in there are subdirs, each of which refers to a python module, and the snippets about that module live in there
[18:34] <jono> so let me explain how a snippet is mad
[18:34] <jono> made
[18:35] <jono> a snippet is just a piece of code that demonstrates something
[18:35] <jono> but what allows us to categorize and show it in Acire are some comments at the top
[18:35] <jono> let's use http://bazaar.launchpad.net/~jonobacon/python-snippets/trunk/annotate/head:/gwibber/sendmessage.py as an examoke
[18:35] <jono> example
[18:35] <jono> the comments with 'SNIPPET' in them are what Acire uses for index and show them
[18:35] <jono> here are the different lines:
[18:35] <jono> [SNIPPET_NAME: Send a message]
[18:36] <jono> this is the text that appears in the sidebar when you have select a snippet category
[18:36] <jono> a short, sharp description of the snippet
[18:36] <jono> [SNIPPET_CATEGORIES: Gwibber]
[18:36] <jono> this is a tag for the snippet
[18:36] <jono> this is the category that appears in the drop-down box
[18:37] <jono> snippets can have multiple categories separated by commas if needed
[18:37] <jono> we have a main list of categories in the CATEGORIES file in the main /usr/share/python-snippets dir
[18:37] <jono> [SNIPPET_DESCRIPTION: Send a message using the Gwibber API]
[18:37] <jono> this is the description that appears under the code - a longer description of what the snippet does
[18:38] <jono> [SNIPPET_AUTHOR: Jono Bacon <jono@ubuntu.com>]
[18:38] <jono> this is who wrote it with their email address
[18:38] <jono> [SNIPPET_LICENSE: GPL]
[18:38] <jono> and this is the license
[18:38] <jono> again, a standard set of licenses are in the LICENSES file in /usr/share/python-snippets
[18:38] <jono> I am happy to accept snippets into the library so long as they use a recognized free software license
[18:39] <jono> so created a snippet is simple:
[18:39] <jono>  1. pick which dir it should be in (or create a new one if your snippet is the first for a given python module)
[18:39] <jono>  2. write the snippet
[18:39] <jono>  3. include these comments at the top
[18:39] <jono>  4. submit it :)
[18:40] <jono> submitting a snippet is explained on https://wiki.ubuntu.com/PythonSnippets
[18:40] <jono> so today we are having a snippets part
[18:40] <jono> party
[18:41] <jono> this is a session in #ubuntu-app-devel where I am encouraging folks to submit snippets for inclusion :)
[18:41] <jono> so this is a great opportunity to join and get involved and share your knowledge
[18:41] <jono> the snippets party takes place at 9pm UTC
[18:42] <jono> and will go on for a few hours, so do come along and join us - it is really cool seeing a snippet that you made show up in the library for everyone to learn from
[18:42] <jono> do you folks want me to explain how you contribute a snippet?
[18:43] <jono> ok cool :)
[18:43] <jono> so first run:
[18:43] <jono> bzr branch lp:python-snippets
[18:43] <jono> this will grab the python-snippets library
[18:43] <jono> now go in and add your snippet
[18:43] <jono> you can add it to an existing directory in there if the snippet is about one of those topics
[18:44] <jono> or feel free to create a new dir for a python module that is not covered in the library yet
[18:44] <jono> when you create your snippet make sure you have the comments at the top of the file
[18:44] <jono> e.g:
[18:44] <jono> # [SNIPPET_NAME: Playing a Pipeline]
[18:44] <jono> # [SNIPPET_CATEGORIES: GStreamer]
[18:44] <jono> # [SNIPPET_DESCRIPTION: Construct and play a pipeline]
[18:44] <jono> # [SNIPPET_AUTHOR: Jono Bacon <jono@ubuntu.com>]
[18:44] <jono> # [SNIPPET_LICENSE: GPL]
 i'm seriously learning a lot this week. contributing as a developer actually seems possible now.
[18:44] <jono> that is awesome! :D
[18:45] <jono> when you have added your snippet, add it to the local library with:
[18:45] <jono> bzr add your-snippet.py
[18:45] <jono> obviously replace your-snippet.py with the filename for your snippet
[18:45] <jono> now commit your changes:
[18:45] <jono> bzr commit
[18:46] <jono> when you run the above command you can enter a short message about what your snippet does
[18:46] <jono> now you need to upload the snippet to Launchpad:
[18:46] <jono> bzr push lp:~<your launchpad username>/python-snippets/<name of your branch>
[18:46] <jono> so an example if I was to upload this I might use the following command:
[18:46] <jono> bzr push lp:~jonobacon/python-snippets/new-gstreamer-snippet
[18:47] <jono> finally,  go to https://code.launchpad.net/python-snippets and you should see your branch listed there. Click on it and when the branch page information page loads click on the Propose for merging link. Add a short description of what you examples do in the Initial Comment box and then click the Propose Merge button.
 QUESTION: is it possible to run acire and make it look in that directory for snippets instead of the default one?
[18:48] <jono> right now, no, but I am adding a feature to do that
[18:49] <jono> what you can do is set up a symbolic link from /usr/share/python-snippets to wherever you checked out the python-snippets code
 QUESTION: Can we use Ground Control to submit a new snippet?
[18:49] <jono> absolutely!
[18:50] <jono> so what I recommend you folks do is check out the python-snippets library, add a snippet and submit it and I can test if it works in Acire
[18:50] <jono> meanwhile I will get as feature into Acire to point it at another directory so it is easier to test it
[18:51] <jono> so we have our snippets party at 9pm UTC, that is two hours away - I recommend you all come along to #ubuntu-app-devel and join us and I can help you get started writing snippets :)
[18:51] <jono> any more questions?
 How about adding snippets as design patterns or algorithms?
[18:52] <jono> absolutely! we have a Patterns dir for design patterns
[18:52] <jono> I would love an algorithms dir too
[18:52] <jono> I am keen to ensure that *all* python snippets are welcome
[18:52] <jono> if they run and they explain how to do something, I will make sure we add it :)
[18:53] <jono> any more questions?
 QUESTION: if I run a snippet in Acire and it crashes, does that bring Acire down too?
[18:53] <jono> usually no
[18:54] <jono> if it does crash Acire, that is a bug and we need to fix it :)
 QUESTION: As Acire grows, how about adding some Search/Sort functions?
[18:55] <jono> I am really keen to add that too
[18:55] <jono> if someone wants to write a patch for this, do go ahead
[18:55] <jono> I think Acire needs a search facility and a find facility for search snippets
 QUESTION: how do contributors handle python versioning idiosyncacies (e.g., 2.5 functions versus 3.x)?
[18:56] <jono> snippets that need to care about Python versions typically do a test in the code
[18:56] <jono> there are a few snippets that have examples of this
[18:56] <jono> awesome
[18:56] <jono> I think we are done
[18:56] <jono> thanks everyone for joining me here!
[18:57] <jono> and I hope to see you all in #ubuntu-app-devel in two hours for the snippets party!
[19:00] <jono> rockstar, all good?
[19:01] <rockstar> jono, starting now?
[19:01] <rockstar> jono, starting now?
[19:01] <jono> yep :)
[19:02] <rockstar> Hi folks.  Apologies in advance for the Lernid users, but I'm not really a slide guy, so you'll just have to follow along.
[19:03] <rockstar> So, dholbach asked me if I'd be willing to talk about writing beautiful code.
[19:03] <rockstar> That puts me in a hard spot, since sometimes I write code that fell out of the ugly tree and hit every branch on the way dawn.
[19:04] <rockstar> As I thought about it though, beautiful code is a process.  It's iterative, and the things you find beautiful now will (probably) be ugly to you in a year.
[19:05] <rockstar> So I began thinking about that process - this is what I'd like to chat about today.
[19:06] <rockstar> Since this is opportunistic developer week, I want to make this a story about opportunities.
[19:08] <rockstar> The scenario I'd like to start with is this:
[19:08] <rockstar> "You've been using Ubuntu and you're feeling very comfortable.  You're in an IRC channel when someone says 'It would be nice if I had an app that would...'"
[19:08] <rockstar> Uh oh.  There's not an app for that.
[19:09] <rockstar> But guess what?  You're an opportunistic developer!  This is an opportunity!
[19:09] <rockstar> QUESTION: <JayFo> will you be going over some tips for making ugly code better? :)
[19:10] <rockstar> ANSWER: Yes, as I said, making ugly code better is a process.  The process is the core of this talk.
[19:10] <rockstar> So, we're going to start a new project.  In this scenario, staying away from ugly code is easy, since there's no ugly code to begin with.
[19:11] <rockstar> When you start a new project, you should get a few things together.  First, you need some version control system (Renaming files to .bak doesn't count)
[19:12] <rockstar> You also should have an issue tracker, even if you haven't even released your code.  This may be as simple as a TODO file.
[19:12] <rockstar> Luckily, we have Launchpad.  Those Launchpad developers are awesome.  They do awesome things.
[19:13] <rockstar> You'll also want a style guide.
[19:14] <rockstar> Programmers have stolen the idea of a style guide from writers and journalists.  A style guide allows you to set some social contracts in how your code is structured.
[19:15] <rockstar> This is a must.  If you don't have this right now in your project, your homework is to go out and establish one.
[19:15] <rockstar> Everyone has different tendencies in their code, so code can get messy as soon as more than one person touches it.
[19:15] <rockstar> QUESTION: <ylynfatt> I assume when you say style guide you mean the same thing as "coding standards"?
[19:16] <rockstar> Yes, same idea.  You should have common idioms.
[19:16] <rockstar> Document this well.  It makes life much better when contributors come aboard.
[19:16] <rockstar> QUESTION: <JayFo> QUESTION: are there any good sample style guides to start with?
[19:17] <rockstar> Python (my favoritest most bestedest language) has a language-wide style guide.
[19:17] <rockstar> It's called PEP 8.
[19:17] <rockstar> http://www.python.org/dev/peps/pep-0008/
[19:18] <rockstar> Basically, it addresses where to put comments, how to name variables/classes/"constants"/functions/etc
[19:18] <rockstar> \sh kindly points out https://dev.launchpad.net/StyleGuides
[19:19] <rockstar> So, on the Launchpad team, there is a style guide that supplements PEP 8, and then we have a style guide for our javascript, etc.
[19:20] <rockstar> I don't personally like some of the standard styles in the Launchpad team.  If I wanted, I could violate those styles, but then no one would approve the code review, and I'd never get anything done.
[19:20] <rockstar> The "social contract" basically allows us all to come to the table with the same expectations for the quality of code.  That's what the style guide gives us.
 QUESTION: Kinda offtopic but is there a reason why space indentation is preferred to tab indentation in PEP 8?
[19:21] <rockstar> somename, the BDFL of Python has spoken.
[19:22] <rockstar> That question is actually quite on-topic.  Sometimes there's no other reason to have the rule than to just have a standard rule.  You can't have both, so there as a choice made.
[19:22] <rockstar> So put together your style guides.  They won't be set in stone.  In fact, they'll be quite fluid.
[19:23] <rockstar> The Launchpad team meets once a week to evaluate if style changes are needed.
[19:23] <rockstar> Just yesterday I proposed a change in style and everyone agreed.
[19:23] <rockstar> QUESTION: <theDtTvB2`MB> When there is a small bug that needs to be fixed real quick, I violate all the style guides and fix it as fast as I can. Does anybody have the same problem as me?
[19:24] <rockstar> I guess I don't know the specific situation, and sometimes you need to do some hacky things to get bugs fixed.  Your style guide shouldn't get in the way of your work.
[19:25] <rockstar> However, when you violate the guide, you're automatically making your code harder to read for others.
[19:25] <rockstar> This actually brings me to my next point (thanks for the easy segway).
[19:25] <rockstar> In whatever language you're working with, the code you write is not for the computer.
[19:26] <rockstar> The computer is going to take that code, translate it into something it understands, and then run it.
[19:26] <rockstar> The code you write is for humans like you and me.
[19:27] <rockstar> Remember that when you're writing the code.  Keep it in mind.  Read your code out loud.
[19:27] <rockstar> C-code, for me, is especially difficult to read aloud, but it helps me to see where something doesn't make sense.
[19:28] <rockstar> Since most documentation standards target US or UK English, your code should kinda make sense that way as well.
[19:29] <rockstar> Sometimes (as in the case of asychronous code) you won't be able to write your code left-to-right/top-to-bottom
[19:30] <rockstar> Use comments in those cases.
[19:31] <rockstar> Alright.  We have about 20 minutes left.  In about 10, I'd like to take and review some "ugly code" that some of you would like to submit.  Please pastebin your examples of "ugly code" and then post them in the chat
[19:32] <rockstar> Okay.  So let's look at another situation, one that is more common, and will probably help you to be better when you actually start projects.
[19:32] <rockstar> You're in IRC, and someone says "<App> is really cool, but it has a problem with <feature-x>"
[19:33] <rockstar> Opportunity awaits!
[19:33] <rockstar> Often, this is where I see "ugly" code, because it's not my code, and it's not in a style I understand immediately.
[19:34] <rockstar> If the project has a style guide, read it before sleuthing to fix the problem.
[19:34] <rockstar> If it doesn't, Thor help you.  :)
[19:35] <rockstar> After you're comfortable with reading the app's code (whether by style guide or fumbling around), find the code you want to work in.
[19:35] <rockstar> As you write your feature, explore the idea of writing a test for that feature.
[19:36] <rockstar> Many languages have great test frameworks that you can use.
[19:37] <rockstar> Testing helps you to avoid embarrassment when (not if) your feature breaks.
[19:37] <rockstar> Make sure, as you write your patch, that you're sticking with common coding conventions.
[19:38] <rockstar> When I say "common" I mean "common the surrounding source code" - Make the code consistent.
[19:38] <rockstar> Once you have your patch (and hopefully test), you're ready to show someone your code.
[19:39] <rockstar> This step is the most important.
[19:39] <rockstar> You're more likely to write ugly code when no one has to see it, and when you don't have to justify why it's ugly.
[19:40] <rockstar> I had a friend who worked as an intern on a proprietary mobile phone platform that said "You would hate this source.  It's terrible, because no one has to see it."
[19:41] <rockstar> Okay, so we submit our code for review.
[19:41] <rockstar> Does anyone want to pastebin their ugly code?
[19:42] <rockstar> QUESTION: <tgalati4> Question first:  Are there any Python style (say PEP 8) checkers?
[19:42] <rockstar> Yes.  On Launchpad, we use pylint (slow, annoying) and pyflakes (doesn't handle exceptions to the rule well)
[19:43] <rockstar> For javascript (my second favoritest language) jslint is what I use.
[19:44] <rockstar> Let's look at the "ugly code" here: http://pastebin.com/1jWRpKCG
[19:44] <rockstar> Thanks to theDtTvB2`MB for putting himself out there.  That's good.
[19:45] <rockstar> Okay, so this javascript code.
[19:45] <rockstar> Javascript is notorious for being a wild west "every man for himself" language.  It's easy to write messy code, it's easy to write code that leaks memory.
[19:46] <rockstar> So as a reviewer, I'm first going to ask what "r" on line 4 is.
[19:46] <rockstar> "r" doesn't tell me anything about the variable, what it contains, or what it's used for.
[19:46] <rockstar> Neither does "c" or "is_DM"
[19:47] <rockstar> That makes this code hard to follow.
[19:49] <rockstar> I also don't have very many comments.
[19:49] <rockstar> Line 53 is actually succinct and rather helpful.
[19:50] <rockstar> Basically, are we starting with the first item in the index?
[19:52] <rockstar> I also am not entirely clear on what the function returns.  It returns a few different things, depending on specific conditions.  A comment at the top of the function would go miles in helping understand what's going on.
[19:52] <rockstar> I rather like jsdoc, and having been using it in my javascript gaming engine I've been working on.
[19:53] <rockstar> By documenting, you help other young developers to start off knowing what the function is doing, and then they can use that context as they read the code.
 And now I starting to forget what some of these line do.
[19:53] <rockstar> theDtTvB2`MB, this is why we strive to write beautiful code.
[19:54] <rockstar> :)
[19:54] <rockstar> Any other questions?
[19:54] <rockstar> Let me point out a potential opportunity here: <tgalati4> Does Lernid have a search feature in the Session window?  That would help to jump to code.
[19:55] <rockstar> QUESTION: <theDtTvB2`MB> Does it need a rewrite?
[19:55] <rockstar> So, rewrites can be scary, especially when you don't have tests (and sometimes even when you do).
[19:56] <rockstar> Usually, when I get into code I wrote that I have forgotten about, I will take some time to sleuth the code, remind myself, and then document the code, and sometimes make slight changes (variable names, etc.)
[19:56] <rockstar> Sometimes code is unsalvagable, and you'll have to re-write it, but just be careful there.  You don't want to be KDE 4.0, do you?  :)
 QUESTION: when does it makes sense to make code more generic (useful in many places). Or to make an abstraction to it?
[19:57] <rockstar> I would say that you should NEVER repeat code.  Never, ever, ever, never, ever.
[19:57] <rockstar> Sometimes, abstractions are harder to understand, so you'll have to "glue" that with good comments.
[19:58] <rockstar> QUESTION: <tgalati4> So can I find good examples of python coding style by doing:  grep python /usr/bin/* ?
[19:58] <rockstar> So, I'm not sure what that would give you.
[19:59] <rockstar> Bazaar's source code is awesome for seeing good coding standards as well as ways to make python perform better.
[19:59] <rockstar> They have some potentially difficult and crazy code that is commented with things like "we have to do this now, or the function won't return fast enough" and things like that.
[20:00] <rockstar> Any more questions?
[20:00] <rockstar> Thanks folks!
[20:01] <rickspencer3> hi all
[20:01] <rickspencer3> shall we dive into quickly-widgets?
[20:01] <rickspencer3> or maybe you need some time to recover from that stellar class by rockstar
[20:03] <rickspencer3> ok, I guess I'll get started
[20:03] <rickspencer3> ok
[20:03] <rickspencer3> my code is ugly
[20:03] <rickspencer3> but functional ;)
[20:03] <rickspencer3> as usual I put my class notes on the wiki
[20:03] <rickspencer3> https://wiki.ubuntu.com/UbuntuOpportunisticDeveloperWeek/Quidgets
[20:04] <rickspencer3> so, quickly-widgets started as a personal side project of mine
[20:04] <rickspencer3> and it got totally out of control
[20:04] <rickspencer3> at some point I discovered it was writing itself at night
[20:04] <rickspencer3> the goal of quickly widgets is to make PyGtk programming more easy and fun
[20:04] <rickspencer3> PyGtk is a fantastic UI tool kit
[20:04] <rickspencer3> It is very powerful, functional, and flexible
[20:05] <rickspencer3> However, at the moment, it lacks some higher order abstractions that developers have come to expect
[20:05] <rickspencer3> The result being that developers have to write reams of code using multiple classes and such for things that are more simple in other frameworks
[20:05] <rickspencer3> for example, popping dialogs, putting data into a grid and such
[20:05] <rickspencer3> so I'm hoping quickly-widgets can fill in some of these use cases
[20:05] <rickspencer3> please note that quickly-widgets is very early in development and experimental
[20:05] <rickspencer3> this means that it is to be buggy and incomplete
[20:06] <rickspencer3> or at least I strongly suspect that it is
[20:06] <rickspencer3> but it also means that if you want to, you can have a lot of influence on how it develops
[20:06] <rickspencer3> so bug reports and branches, more than welcome
[20:06] <rickspencer3> btw
[20:06] <rickspencer3> so what is Quidgets?
[20:06] <rickspencer3> "Quidgets" is the original name of quickly-widgets
[20:06] <rickspencer3> it was a silly name
[20:06] <rickspencer3> I made it up without really thinking
[20:06] <rickspencer3> the project is still called Quidgets
[20:06] <rickspencer3> so you can get the code:
[20:06] <rickspencer3> $bzr branch lp:quidgets
[20:06] <rickspencer3> quickly-widgets is currently in universe for Lucid
[20:07] <rickspencer3> (this scares me a bit, but what the heck ;) )
[20:07] <rickspencer3> it is not packaged for Karmic
[20:07] <rickspencer3> though if someone wanted to do that, I would not complain too much ;)
[20:07] <rickspencer3> currently, quickly widgets has two modules
[20:07] <rickspencer3> quickly.prompts
[20:07] <rickspencer3> and quickly.widgets
[20:07] <rickspencer3> quickly.widgets has some general widgets
[20:07] <rickspencer3> but also some widgets for displaying data, basically extending TreeView and making it simpler to use
[20:07] <rickspencer3> I'll discuss each of these three areas in a bit more depth
[20:08] <rickspencer3> But first, Questions?
[20:08] <ClassBot> oskude asked: does quickly-widgets work with or without glade (the editor) ?
[20:08] <rickspencer3> currently there is no glade integration
[20:08] <rickspencer3> I don't think it would be too hard to add this, but it hasn't been tackled yet
[20:08] <rickspencer3> I think to do this would require crafting a library file in XML
[20:09] <rickspencer3> but then also making sure the properties were properly setable in the glade propery editor
[20:09] <rickspencer3> Before we look at the modules, a word on the mental model of using quickly-widgets
[20:09] <rickspencer3> There are 3 "levels" to consuming quickly-widgets
[20:09] <rickspencer3> Most of the time, you should be fine with the first level, which is the "Use" level
[20:09] <rickspencer3> At this level, you just make a one-liner that uses the API and does something useful
[20:10] <rickspencer3> like, get as string from the user:
[20:10] <rickspencer3> quickly.prompts.string("My Title","Give me a string","default val")
[20:10] <rickspencer3> or maybe you want do display the data in a dictionary:
[20:10] <rickspencer3> dg = DictionaryGrid(my_list_of_dicts)
[20:10] <rickspencer3> dg.show()
[20:10] <rickspencer3> see, you just go ahead and "use" the classes
[20:10] <rickspencer3> sometimes you want to tweak something a bit. In these cases you go to the configure level.
[20:10] <rickspencer3> When you are doing "configure" you might end up a using the underlying PyGtk API a bit
[20:10] <rickspencer3> For example, a dictionary grid is really just a Treeview
[20:10] <rickspencer3> So if you want to configure the title for a column, you might go
[20:11] <rickspencer3> dg.get_columns()[0].set_title("New Title")
[20:11] <rickspencer3> some of the configuration might be done in the quickly.widgets library though
[20:11] <rickspencer3> like if you want to display certain keys from your dictionary, you can use a list of keys to display
[20:11] <rickspencer3> keys = ["key1","key2']
[20:11] <rickspencer3> dg = DictionaryGrid(my_dict,keys=keys)
[20:11] <rickspencer3> I'll talk about the specifics here a bit later
[20:11] <rickspencer3> but the point is, you can go beyond the one liner if you need to
[20:12] <rickspencer3> so if you start with the one liner, but then need to expand out a bit
[20:12] <rickspencer3> you don't throw away your code, just add some "configure" code
[20:12] <rickspencer3> let's say you get back a feature request from a user or customer, and you need to do something that is not suppported by quickly-widgets through using or configuring
[20:12] <rickspencer3> well, quickly-widgets strives to consume PyGtk in such a way that you can extend classes as needed to accomplish your goals
[20:12] <rickspencer3> for example, if you want a grid that displays data from a certain SQL database somewhere, you can inherit from DictionaryGrid and add the SQL functionality.
[20:12] <rickspencer3> This is exactly what CouchGrid does, but for generally desktopcouchy things
[20:12] <rickspencer3> So, before I discuss using the prompts a bit, any questions?
[20:13] <ClassBot> \sh asked: which audience did you have in mind when you started Quickly?
[20:13] <rickspencer3> well, fundamentally I was scratching my own itch
[20:13] <rickspencer3> I was working on bughugger and thought ...
[20:13] <rickspencer3> "I cannot believe I am writing this same TreeView code *again*"
[20:14] <rickspencer3> I vowed at that moment to never craft a TreeView again
[20:14] <rickspencer3> though I don't mind writing code that writes TreeViews ;)
[20:14] <rickspencer3> beyond me, I am thinking about application writers on Ubuntu
[20:14] <rickspencer3> so I don't mind making some distro specific assumptions
[20:15] <rickspencer3> ultimately, I am thinking about folks who, like me, often can visualize and app, and want to get straight to the fun part
[20:15] <rickspencer3> without bothering with all the boiler plate of a powerful library like Gtk
[20:15] <rickspencer3> more questions?
[20:16] <rickspencer3> ok
[20:16] <rickspencer3> prompts
[20:16] <rickspencer3> Prompts are basically dialogs that you can use to interact with the user without writing too much code
[20:16] <rickspencer3> rather than creating a PyGtk dialog or similar yourself, and then populating it, for certain scenarios a prompt in quickly-widgets can take care of it for you
[20:16] <rickspencer3> the prompts module is right under quickly, so you can get it like this:
[20:16] <rickspencer3> from quickly import prompts
[20:16] <rickspencer3> or just quickly.prompts.string() if you want
[20:16] <rickspencer3> there are three kinds of prompts
[20:16] <rickspencer3> the first kind just displays info the the user
[20:16] <rickspencer3> these take a couple of strings from you and display a message box to the user with the appropriate icon
[20:17] <rickspencer3> so, you can go
[20:17] <rickspencer3> prompts.error("Title for the Error Dialog","Error text")
[20:17] <rickspencer3> this will pop up a little dialog that says "Error text"
[20:17] <rickspencer3> with a dialog error icon next to it
[20:17] <rickspencer3> there is also prompts.warning and prompts.info
[20:17] <rickspencer3> they works the same as error
[20:17] <rickspencer3> The next kind of prompt collects some info from the user
[20:18] <rickspencer3> the kind of prompts built in of this kind are:
[20:18] <rickspencer3> string, date, integer, decimal, and price
[20:18] <rickspencer3> they all take care of displaying an appropriate widget for the user input for you
[20:18] <rickspencer3> like a textbox for a string, a calendar for a date, and a spinner appropriately formatted if appropriate
[20:18] <rickspencer3> they let you set a title, a message, a default value, and in the case of the numeric ones some other defaults if you want
[20:18] <rickspencer3> the functions all return a gtk.RESPONSE and a value
[20:18] <rickspencer3> make sure you check the response because if the user cancelled, you want to do the right thing
[20:19] <rickspencer3> so to get a string, go:
[20:19] <rickspencer3> response, val = quickly.prompts.string()
[20:19] <rickspencer3> if response == gtk.RESPONSE_OK:
[20:19] <rickspencer3>  #do something with val
[20:19] <rickspencer3> where val is a string
[20:19] <rickspencer3> you can get a date in the same way
[20:19] <rickspencer3> when dealing with date values are tuples in the form of integers for (year,month,day)
[20:19] <rickspencer3> where month is zero indexed (Jaunary is 0, December is 11)
[20:20] <rickspencer3> and you use tuples for the default value in teh same way
[20:20] <rickspencer3> so:
[20:20] <rickspencer3> response, date = quickly.widgets.date("Title String","Enter your birthday",(1968,03,22))
[20:20] <rickspencer3> so that's *April* because the months are zero indexed
[20:20] <rickspencer3> if you want to get an integer, you can set min_value, and max_value as well
[20:20] <rickspencer3> if you look at the doc string, you can see other options as well
[20:20] <rickspencer3> decimal and price are also rich in options
[20:20] <rickspencer3> price is just decimal, but with 2 decimal places set
[20:20] <rickspencer3> however, they all work basically the same way, response, val = function()
[20:21] <rickspencer3> if you need to configure the prompt a bit more, for each function, there is a symetrical class that you can use
[20:21] <rickspencer3> so for string(), if you want to own the dialog for some reason, you can use StringPrompt
[20:21] <rickspencer3> sp = StringPrompt(title, text, default_string)
[20:21] <rickspencer3> then you can party on sp if you want
[20:21] <rickspencer3> there is a similar dialog for date, integer, decimal, and price
[20:21] <rickspencer3> each has a "get_value()" function to extract the value
[20:21] <rickspencer3> The last set of prompts are FileChooserDialogs
[20:21] <rickspencer3> they work the same way
[20:22] <rickspencer3> response, path = quickly.prompts.choose_directory(title)
[20:22] <rickspencer3> there is choose_directory, save_image_file, and open_image_file
[20:22] <rickspencer3> there are classes for these as well
[20:22] <rickspencer3> DirectoryChooserDialog, OpenImageDialog, and SaveImageDialog
[20:22] <rickspencer3> these lack get_value, because they are just subclasses of FileChooserDialog
[20:22] <rickspencer3> which already has a get_filename() function
[20:22] <rickspencer3> before I talk about the gtk.Widgets, any questions?
[20:23] <ClassBot> tgalati4 asked: I noticed that quidgets is only packaged for Lucid, no Karmic.  Any plans?
[20:23] <rickspencer3> I'm not planning this myself
[20:23] <rickspencer3> but I would be happy to work with anyone who wanted to do this
[20:24] <rickspencer3> btw, I should have mentioned that the package name is quickly-widgets in universe
[20:24] <rickspencer3> alright
[20:24] <rickspencer3> moving on to quickly.widgets
[20:24] <rickspencer3> for widgets, there are a few miscelaneous ones, and then the grid related ones
[20:24] <rickspencer3> I'll start with the miscelaneous ones
[20:24] <rickspencer3> the most miscelaneous one is
[20:24] <rickspencer3> from quickly.widgets.camera_button import CameraButton
[20:25] <rickspencer3> CameraButton wraps up the PyGame web cam API and serves up pixbufs
[20:25] <rickspencer3> I don't like how this is implemented at the moment, and am planning to pull it into it's own package for a while, until I can make it work well
[20:25] <rickspencer3> however, it's kinda fun when it works
[20:25] <rickspencer3> there's also a subclass of button called PressAndHold button
[20:25] <rickspencer3> this one is quite useful and functional
[20:25] <rickspencer3> this guy fires a signal every 250ms, so long as the user is holding the button down
[20:26] <rickspencer3> so this allows you to do something while the user is holding down a button
[20:26] <rickspencer3> I use this in photobomb to manage rotation of times for example
[20:26] <rickspencer3> first, create the button, then connect to the signal
[20:26] <rickspencer3>         button = PressAndHoldButton()
[20:26] <rickspencer3>         button.connect("tick",action)
[20:26] <rickspencer3> then write a function that does something every time the signal fires
[20:26] <rickspencer3> def action(self, widget=None, data=None):
[20:26] <rickspencer3>  #do something every 250ms
[20:27] <rickspencer3> for photobomb "something" is selected_item.rotate() or such
[20:27] <rickspencer3> the last misc. quickly.widget is
[20:27] <rickspencer3> from quickly.widgets.asynch_task_progressbox import AsynchTaskProgressBox
[20:27] <rickspencer3> in general, you should avoid threads in your python app
[20:27] <rickspencer3> you should use things like gobject.timeout_add() or gobject.idle_add()
[20:27] <rickspencer3> and the gio library
[20:27] <rickspencer3> however, for times when you absolutely must use a thread AsynchTaskProgressBox can make it easier for you
[20:27] <rickspencer3> this derives from gtk.ProgressBox, so it supplies some throbbing UI for you if you need it
[20:28] <rickspencer3> the basic idea is to write a function that you want to run on a thread
[20:28] <rickspencer3> I usually call this a task
[20:28] <rickspencer3> create a dictionary of parameters if you want to pass some params to the function
[20:28] <rickspencer3> create the AsynchTaskProgressBox
[20:28] <rickspencer3> if you want to know when the task is done, connect to the complete event
[20:28] <rickspencer3> here's some photobomb code for example
[20:28] <rickspencer3> params = {"directory":directory}
[20:28] <rickspencer3> pb = AsynchTaskProgressBox(self.__load_task, params, False)
[20:28] <rickspencer3> pb.connect("complete",self.__load_task_complete)
[20:28] <rickspencer3> for your task, you can simulate a killable thread (in python you can't really kill a thread, just wait for it to end)
[20:29] <rickspencer3> if every
[20:29] <rickspencer3> if *ever* even
[20:29] <rickspencer3> you do this by checking a special key that is added to params called "kill"
[20:29] <rickspencer3> if it's set to True, you can stop working
[20:29] <rickspencer3> here's a bit of code from photobomb to demonstrate
[20:29] <rickspencer3>     def __load_task(self, params):
[20:29] <rickspencer3>         pictures_dir = params["directory"]
[20:29] <rickspencer3>         images = []
[20:29] <rickspencer3>         files = os.listdir(pictures_dir)
[20:29] <rickspencer3>         for f in files:
[20:29] <rickspencer3>             try:
[20:29] <rickspencer3>                 if params["kill"]:
[20:29] <rickspencer3>                     return None
[20:29] <rickspencer3>                 #etc....
[20:29] <rickspencer3> So the last bit about quickly-widgets is about Grids and Filters and stuff
[20:29] <rickspencer3> before I do that, any questions so far?
[20:30] <ClassBot> stevec33 asked: Why is it best to avoid threads?
[20:31] <rickspencer3>  because the implentation in Python leaves a lot to be desired
[20:31] <rickspencer3>  like there is a global lock and scuh
[20:31] <rickspencer3>  they are not true threads that get deployed and run seperately on CPUs and such
[20:31] <rickspencer3>  but mostly, it's really hard to write code that does not have bad bugs in it
[20:32] <rickspencer3> this is especially true with PyGtk
[20:32] <rickspencer3> you have to call threads_enter() and threads_leave() and all this when updating the UI
[20:32] <rickspencer3> or it goes quite haywire
[20:33] <rickspencer3> ok
[20:33] <rickspencer3> on to grids
[20:33] <rickspencer3> lots of the code in quickly-widgets is about presenting data to users in a TreeView
[20:33] <rickspencer3> in PyGtk, gtk.TreeView handles both displaying grid data and data in trees
[20:33] <rickspencer3> quickly-widgets focuses on the Grid
[20:33] <rickspencer3> and totally ignores the tree case
[20:34] <rickspencer3> trees are UI elements where there are nested nodes with those little disclosure triangles and such
[20:34] <rickspencer3> so, grids
[20:34] <rickspencer3> the essentially scenario is that you have some tabular data to display
[20:34] <rickspencer3> gtk.TreeView can let you display this in any manner you like
[20:34] <rickspencer3> so long as you:
[20:34] <rickspencer3> 1. Create a TreeView
[20:34] <rickspencer3> 2. Cerate a treeview model store of some kind
[20:34] <rickspencer3> 3. create columns
[20:34] <rickspencer3> 4. create cellrenders for each column
[20:34] <rickspencer3> 5. popluate the treeview model
[20:35] <rickspencer3> each of these steps taking multiple lines of code *per column*
[20:35] <rickspencer3> and this does not include letting users change the values in the grid
[20:35] <rickspencer3> filtering
[20:35] <rickspencer3> adding data after it is created, etc...
[20:35] <rickspencer3> from quickly.widgets.dictionary_grid import DictionaryGrid tries to handle this for you in essentially, one line of code
[20:35] <rickspencer3> the basic interaction is that you create a DictionaryGrid by handing it a list of dictionary, and it makes a TreeView for you
[20:36] <rickspencer3> you just show it and add it to your form
[20:36] <rickspencer3> Here's a bit from the dictionary grid test program
[20:36] <rickspencer3> first, a list of dictionaries
[20:36] <rickspencer3> dicts = [{"key?": True, "price":0.00,"tags" : "aaa bbb ccc","_foo":"bar","bing count":20},
[20:36] <rickspencer3>                  {"ID": 11, "key?": False, "price":2.00,"tags" : "bbb ccc ddd","_foo":"bar"},
[20:36] <rickspencer3>                  {"key?": True, "price":33.00,"tags" : "ccc ddd eee","_foo":"bar","bing count":15},
[20:36] <rickspencer3>                  {"ID": 3, "tags" : "ddd eee fff","_foo":"bar"},
[20:36] <rickspencer3>                  {"ID": 4, "price":5.00,"_foo":"bar"}]
[20:36] <rickspencer3> then, create the DictionaryGrid:
[20:36] <rickspencer3> grid = DictionaryGrid(dicts)
[20:36] <rickspencer3> seriously, that;s all it takes to show the data in the dictionaries to a user
[20:36] <rickspencer3> if you want the user to be able to edit the grid, set it to editable:
[20:37] <rickspencer3> grid.editable = True
[20:37] <rickspencer3> note that setting some of the properties, including editable will cause the grid to reset itself
[20:37] <rickspencer3> if it's editable, the user can change the data in the dictionary
[20:37] <rickspencer3> there are some properties that you can use to extract the data
[20:37] <rickspencer3> like
[20:37] <rickspencer3> grid.rows
[20:38] <rickspencer3> this gives you all the rows
[20:38] <rickspencer3> where as
[20:38] <rickspencer3> grid.selected_rows gives you the currently selected row
[20:38] <rickspencer3> some handy functions you get for free, like
[20:38] <rickspencer3> grid.remove_selected_rows()
[20:39] <rickspencer3> remove_selected_rows
[20:39] <rickspencer3> oops
[20:39] <rickspencer3> you can add to your grid by appending rows
[20:39] <rickspencer3> grid.append_row(my_dict)
[20:39] <rickspencer3> if you want to add an empty row
[20:39] <rickspencer3> append_row({})
[20:39] <rickspencer3> then if the grid is editable, the user can fill itin
[20:40] <rickspencer3> by default, the grid will display a column for every key it encounters UNLESS that key starts with "__" (two underscores), in which case it will be ignored
[20:40] <rickspencer3> if you want to control the keys displayed, you can do this when you create it:
[20:40] <rickspencer3> grid = DictionaryGrid(dicts,list_of_keys)
[20:40] <rickspencer3> or you can set the keys later
[20:40] <rickspencer3> grid.keys = list_of_keys
[20:40] <rickspencer3> this causes the grid to reset, btw
[20:40] <rickspencer3> Columns will sort properly most of the time
[20:40] <rickspencer3> this is accomplished by having each column be a certain type
[20:40] <rickspencer3> there is the default StingColumn, but there is also IntegerColumn, CurrencyColumn, TagsColumn, and CheckColumn
[20:41] <rickspencer3> by "extending" GridColumn you can create your own column types if you need to
[20:41] <rickspencer3> DictionaryGrid tries to guess the right column type to use based on the name of the key
[20:41] <rickspencer3> So if you choose your key names correctly, you can get a lot of good functionality for free
[20:41] <rickspencer3> for example, and key that ends with "?" DictionaryGrid will assume it is a boolean, and use CheckBoxes to show the values
[20:41] <rickspencer3> and provide the appropriate sortign for you
[20:41] <rickspencer3> the key "price" is assumed to be currency
[20:41] <rickspencer3> anything ending in count will be an IntegerColumn, same with a key called "id"
[20:41] <rickspencer3> a key called "tags" will be a tags column
[20:41] <rickspencer3> tags columns are mostly important for filtering, which I will discuss in a moment
[20:42] <rickspencer3> you can control the columntypes manually if you want, by passing in "Type Hints"
[20:42] <rickspencer3> here's some code from the tests:
[20:42] <rickspencer3>         keys = ["id","price","bool?","foo"]
[20:42] <rickspencer3>         hints = {"id":StringColumn, "price":IntegerColumn,
[20:42] <rickspencer3>                  "bool?":CurrencyColumn,"foo":CheckColumn}
[20:42] <rickspencer3>         dicts = [{"price":100,"id":"asdfas","bool?":10.01,"foo":True}]
[20:42] <rickspencer3>         grid = DictionaryGrid(dicts, keys, hints)
[20:42] <rickspencer3> in this case hints are overriding the defaults
[20:42] <rickspencer3> so I should talk about filtering next, but first, questions?
[20:43] <rickspencer3> I hope there are no question be my content is so riveting, and the clarity is so profound
[20:43] <rickspencer3> :)
[20:43] <rickspencer3> moving on ...
[20:43] <rickspencer3> so one cool thing about gtk.TreeView is the filtering capabilities
[20:44] <rickspencer3> Filtering even pretty long lists works really fast
[20:44] <rickspencer3> but this is a TON of work in PyGtk
[20:44] <rickspencer3> from quickly.widgets.grid_filter import GridFilter makes a filter UI for you
[20:44] <rickspencer3> this will let the user add filters to filter columns
[20:44] <rickspencer3> if you've seen the bughugger UI, then you have seen GridFilter and DictionaryGrid in action
[20:44] <rickspencer3> you just need to hand it a Grid to filter
[20:44] <rickspencer3> it will pick up filter types from the GridColumns in the Grid
[20:44] <rickspencer3> So for example columns with strings will get a filter with "contains substring" while a column with numbers will get ">,<.=", etc...
[20:45] <rickspencer3> a tags column gets "contains one of these tags", "contains all of these tags", etc...
[20:45] <rickspencer3> all this just by creating it:
[20:45] <rickspencer3> filt = GridFilter(grid)
[20:45] <rickspencer3> filt.show()
[20:45] <rickspencer3> if you want to override the default filter types, you can pass in hints
[20:45] <rickspencer3> this works pretty much like in the grid
[20:45] <rickspencer3> you pass in a dictionary that matches up keys to filter types
[20:45] <rickspencer3> well, actually to filter combos, but that's a bit more detail than necessary
[20:45] <rickspencer3> there are StringFitlerCombo, TagsFilterCombo, CheckFilterCombo etc...
[20:46] <rickspencer3> there is also blank filter combo that you can use to easily make your own filters
[20:46] <rickspencer3> for example, in bughugger I created a custom filter to filter status and importance like this:
[20:46] <rickspencer3>   sw_filter2 = BlankFilterCombo()
[20:46] <rickspencer3>   sw_filter2.append("=",lambda x,y: convert_to_num(x) == float(y) )
[20:46] <rickspencer3>   sw_filter2.append("<",lambda x,y: convert_to_num(x) < float(y) )
[20:46] <rickspencer3>   sw_filter2.append(">",lambda x,y: convert_to_num(x) > float(y) )
[20:46] <rickspencer3>   sw_filter2.append("<=",lambda x,y: convert_to_num(x) <= float(y) )
[20:46] <rickspencer3>   sw_filter2.append(">=",lambda x,y: convert_to_num(x) >= float(y) )
[20:46] <rickspencer3> filter_hints = {"status":sw_filter,"importance":sw_filter2}
[20:46] <rickspencer3> each call to append adds a string and a function call
[20:46] <rickspencer3> the function gets called when the users changes the filter in some way
[20:47] <rickspencer3> the function should return True to show the row
[20:47] <rickspencer3> or False to hide the row
[20:47] <rickspencer3> lastly I'll discuss CouchGrid
[20:47] <rickspencer3> but first, Questions?
[20:47]  * rickspencer3 tap tap
[20:47] <rickspencer3> is this thing on?
[20:48] <ClassBot> tgalati4 asked: Besides bughugger and photobomb, any other apps using quidgets that we can use for reference?
[20:48] <rickspencer3> I don't know
[20:48] <rickspencer3> I get a lot of questions about using the widgets
[20:48] <rickspencer3> but I haven't tracked what folks are doing with it
[20:48] <rickspencer3> sorry :/
[20:48] <rickspencer3> ok
[20:49] <rickspencer3> before we break, I'll touch on CouchGrid
[20:49] <rickspencer3> the flagship of the quickly-widgets package
[20:49] <rickspencer3> I feel this has been talked about a lot
[20:49] <rickspencer3> In Lucid, a CouchGrid is a DictionaryGrid
[20:49] <rickspencer3> this is different than the CouchGrid that was desktopcouch.records.couch_grid import CouchGrid
[20:50] <rickspencer3> in Lucid you get all the sorting and filtering of DictionaryGrid, plus persistance in desktopcouch
[20:50] <rickspencer3> you need to define a database and a record type
[20:50] <rickspencer3> if you want, you can pass in a dictionary with some starter data as well
[20:50] <rickspencer3> here is some code from the GridFilter test app
[20:50] <rickspencer3>     database_name = "couch_widget_test"
[20:50] <rickspencer3>     record_type = "couch_grid_filter_test"
[20:50] <rickspencer3>     hints = {}
[20:50] <rickspencer3>     grid = CouchGrid(database_name, record_type=record_type, dictionaries=dicts)
[20:50] <rickspencer3>     grid.show()
[20:50] <rickspencer3>     filt = GridFilter(grid,hints)
[20:50] <rickspencer3>     filt.show()
[20:50] <rickspencer3> this sets up a database for you
[20:50] <rickspencer3> if the databaes is there and there are records already
[20:50] <rickspencer3> it displays those for you!
[20:51] <rickspencer3> if there are new records it persists them for you
[20:51] <rickspencer3> so, that
[20:51] <rickspencer3> s the last bit of content I had planned
[20:51] <rickspencer3> Questions?
[20:53] <rickspencer3> okay
[20:53] <rickspencer3> so, if you're hacking and have questions, want to contribute
[20:53] <rickspencer3> etc...
[20:54] <rickspencer3> join #quickly any time and ask away
[20:54] <rickspencer3> again, the project is early, so feedback and contributions can have a big impact at this point
[20:54] <rickspencer3> this is community developed software, so it's there to be molded by the community :)
[20:54] <ClassBot> tgalati4 asked: What's on the roadmap on quidgets?  What's the burning next todo item?
[20:55] <rickspencer3> thanks for the question tgalati4
[20:55] <rickspencer3> next step is to get some feedback on the Grid related stuff
[20:55] <rickspencer3> and fix bugs
[20:55] <rickspencer3> I think that saves the most work there
[20:55] <rickspencer3> also, I'd like to make the web cam button good
[20:56] <rickspencer3> someone yesterday suggest gstreamer, I should give that a try
[20:56] <rickspencer3> also, there may be more file chooser dialogs for the prompts
[20:56] <rickspencer3> I'd like to add any widgets that folks like that they would like to find an upstream home for
[20:56] <rickspencer3> but one of the most immediate burning things for me is to write documentation
[20:58] <rickspencer3> please note that there is a fair amount of documentation already in the code itself
[20:58] <rickspencer3> and you can access this with pydocs
[20:59] <rickspencer3> thanks everyone!
[20:59] <rickspencer3> I'm looking forward to working with folks to make quickly-widgets more functional and more easy and more fun
[20:59] <rickspencer3> :)
[21:03] <malev> hey, where does the talks logs are stored?
[21:03] <malev> where are store the chat logos? (better this way)
[21:04] <ausimage> malev there linked from the wiki paage with the schedule
[21:05] <malev> ausimage: thanks!
[21:05] <ausimage> no
[21:05] <ausimage> np
[21:05] <ausimage> :/
[21:05] <ausimage> fingers :S