<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Lateral Opinion (qt)</title><link>http://ralsina.com.ar</link><description></description><language>en</language><lastBuildDate>Mon, 10 Mar 2014 12:31:28 GMT</lastBuildDate><generator>http://getnikola.com/</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Qt Mac Tips</title><link>http://ralsina.com.ar/weblog/posts/qt-mac-tips.html</link><description>&lt;div&gt;&lt;p&gt;My team has been work­ing on port­ing some PyQt stuff to Mac OS­X, and we have run
in­to sev­er­al Qt bugs, sad­ly. Here are two, and the work­arounds we found.&lt;/p&gt; 
 &lt;p&gt;&lt;strong&gt;Na­tive di­alogs are bro­ken.&lt;/strong&gt;&lt;/p&gt; 
 &lt;p&gt;Us­ing  &lt;a class="reference external" href="http://qt-project.org/doc/qt-4.8/qfiledialog.html#getExistingDirectory"&gt;QFile­Di­a­log.ge­tEx­ist­ingDi­rec­to­ry&lt;/a&gt; 
we no­ticed the fol­low­ing symp­tom­s:&lt;/p&gt; 
 &lt;ul class="simple"&gt;
&lt;li&gt;If you do noth­ing, the di­a­log went away on its own af­ter about 20 sec­ond­s.&lt;/li&gt; 
 &lt;li&gt;Af­ter you used it on­ce, it may pop up and dis­ap­pear im­me­di­ate­ly. Or not.&lt;/li&gt; 
 &lt;/ul&gt;
&lt;p&gt;So­lu­tion: use the  &lt;a class="reference external" href="http://qt-project.org/doc/qt-4.8/qfiledialog.html#Option-enum"&gt;Don­tUse­N­a­tive­Di­a­log op­tion.&lt;/a&gt;&lt;/p&gt; 
 &lt;p&gt;&lt;strong&gt;Wid­gets in QTreeWid­getItems don't scrol­l.&lt;/strong&gt;&lt;/p&gt; 
 &lt;p&gt;When you use Wid­gets in­side the items of a QTreeWid­get (which I know, is not a com­mon case, but
hey, it hap­pen­s), the wid­gets don't scroll with the item­s.&lt;/p&gt; 
 &lt;p&gt;So­lu­tion: use the  &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-graph­ic­ssys­tem&lt;/span&gt;   raster&lt;/tt&gt;  op­tion­s. You can even in­ject them in­to
 &lt;tt class="docutils literal"&gt;argv&lt;/tt&gt;  if the plat­form is  &lt;tt class="docutils literal"&gt;dar­win&lt;/tt&gt;.&lt;/p&gt;&lt;/div&gt;</description><category>pyqt</category><category>qt</category><category>python</category><category>programming</category><guid>http://ralsina.com.ar/weblog/posts/qt-mac-tips.html</guid><pubDate>Sat, 25 Aug 2012 14:24:36 GMT</pubDate></item><item><title>The Future of PyQt by Example</title><link>http://ralsina.com.ar/weblog/posts/the-future-of-pyqt-by-example.html</link><description>&lt;div&gt;&lt;p&gt;Three years ago, I start­ed a se­ries of long posts called "PyQt by Ex­am­ple". It reached five post­s
be­fore I aban­doned for a se­ries of rea­sons that don't mat­ter any­more. That se­ries is com­ing back­
s­tart­ing next week, rewrit­ten, im­proved and ex­tend­ed.&lt;/p&gt; 
 &lt;p&gt;It will do so in a new site, and the "old" posts will be re­tired to an ar­chive page. Why? Well,
the tech­nolo­gies used in some of them are ob­so­lete or don't quite work nowa­days. So, the new
ver­sions will be the pre­ferred ones.&lt;/p&gt; 
 &lt;p&gt;And while I am not promis­ing any­thing, I have enough writ­ten to make this some­thing quite longer,
­more nice­ly lay­out­ed, more in­ter­est­ing and make it cov­er more ground. BUT, while do­ing some
checks on the traf­fic sta­tis­tics for the old post­s, some things popped out.&lt;/p&gt; 
 &lt;dl class="docutils"&gt;
&lt;dt&gt;This was very popular&lt;/dt&gt;
&lt;dd&gt;About 60% of my site's traffic goes to those five posts. Out of about 1200 posts over
12 years, &lt;strong&gt;60%&lt;/strong&gt; of the viewers go to the &lt;strong&gt;0.4%&lt;/strong&gt; of the pages. That is a lot.&lt;/dd&gt;
&lt;dt&gt;It's a long tail&lt;/dt&gt;
&lt;dd&gt;The traffic has not decreased in three years. If anything, it has &lt;em&gt;increased&lt;/em&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;div class="figure"&gt;
&lt;img alt="https://p.twimg.com/Aw0MHhoCAAAXmro.png:large" src="https://p.twimg.com/Aw0MHhoCAAAXmro.png:large" style="width: 80%;"&gt;
&lt;p class="caption"&gt;A long and  &lt;em&gt;tall&lt;/em&gt;  tail.&lt;/p&gt; 
 &lt;/div&gt;
&lt;p&gt;So, all this means there is a de­sire for PyQt doc­u­men­ta­tion that is not sat­is­fied. I am not
­sur­prised: PyQt is great, and the rec­om­mend­ed book is not free, so there is bound to be a lot
of de­mand.&lt;/p&gt; 
 &lt;p&gt;And, here's the not-­so-rosy bit: I had un­ob­tru­sive, rel­e­van­t, out­-of-the-way-but-vis­i­ble ad­s
in those pages for more than two years. Of the 70000 unique vis­i­tors, not even one clicked on
an ad. Don't wor­ry, I was not ex­pect­ing to get mon­ey out of them (although I would love to
­some day col­lect a $100 check in­stead of hav­ing google hold my mon­ey for me ad eter­num).&lt;/p&gt; 
 &lt;p&gt;But re­al­ly? Not even  &lt;em&gt;one&lt;/em&gt;  ad click? In more than two years, thou­sands of peo­ple? I have to
­won­der if I just at­tract cheap peo­ple ;-)&lt;/p&gt;&lt;/div&gt;</description><category>python</category><category>pyqt</category><category>qt</category><category>programming</category><guid>http://ralsina.com.ar/weblog/posts/the-future-of-pyqt-by-example.html</guid><pubDate>Mon, 02 Jul 2012 22:17:00 GMT</pubDate></item><item><title>Ubuntu One APIs by Example (part 1)</title><link>http://ralsina.com.ar/weblog/posts/BB1006.html</link><description>&lt;div&gt;&lt;p&gt;One of the nice things about work­ing at Canon­i­cal is that we pro­duce open source soft­ware.
I, specif­i­cal­ly, work in the team that does the desk­top clients for
 &lt;a class="reference external" href="https://one.ubuntu.com"&gt;Ubun­tu One&lt;/a&gt;  which is a re­al­ly cool job, and a re­al­ly cool piece
of soft­ware. How­ev­er, one thing not enough peo­ple know, is that we of­fer damn nice APIs
­for de­vel­op­er­s. We have to, since all our client code is open source, so we need those
APIs for our­selves.&lt;/p&gt; 
 &lt;p&gt;So, here is a small tu­to­ri­al about us­ing some of those APIs. I did it us­ing Python and
PyQt for sev­er­al rea­son­s:&lt;/p&gt; 
 &lt;ul class="simple"&gt;
&lt;li&gt;Both are great tools for pro­to­typ­ing&lt;/li&gt; 
 &lt;li&gt;Both have good sup­port for the re­quired stuff (D­Bus, HTTP, OAu­th)&lt;/li&gt; 
 &lt;li&gt;It's what I know and en­joy. Since I did this code on a sun­day, I am
not go­ing to use oth­er things.&lt;/li&gt; 
 &lt;/ul&gt;
&lt;p&gt;Hav­ing said that, there is noth­ing python-spe­cif­ic or Qt-spe­cif­ic in the code. Where
I do a HTTP re­quest us­ing Qt­Net­work, you are free to use lib­soup, or what­ev­er.&lt;/p&gt; 
 &lt;p&gt;So, on to the nuts and bolt­s. The main pieces of Ubun­tu One, from a in­fras­truc­ture
per­spec­tive, are Ubun­tu SSO Clien­t, that han­dles us­er reg­is­tra­tion and login, and
Sync­Dae­mon, which han­dles file syn­chro­niza­tion.&lt;/p&gt; 
 &lt;p&gt;To in­ter­act with them, on Lin­ux, they of­fer DBus in­ter­faces. So, for ex­am­ple, this is
a frag­ment of code show­ing a way to get the Ubun­tu One cre­den­tials (this would nor­mal­ly
be part of an ob­jec­t's __init__):&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="c"&gt;# Get the session bus&lt;/span&gt;
&lt;span class="n"&gt;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dbus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SessionBus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="c"&gt;# Get the credentials proxy and interface&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.ubuntuone.Credentials"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="s"&gt;"/credentials"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;follow_name_owner_changes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Connect to signals so you get a call when something&lt;/span&gt;
&lt;span class="c"&gt;# credential-related happens&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_iface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dbus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_proxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"com.ubuntuone.CredentialsManagement"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect_to_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'CredentialsFound'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_found&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect_to_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'CredentialsNotFound'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_not_found&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect_to_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'CredentialsError'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Call for credentials&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_credentials&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You may have no­ticed that get_­cre­den­tials does­n't ac­tu­al­ly  &lt;em&gt;re­turn&lt;/em&gt;  the cre­den­tial­s. What
it does is, it tells Sync­Dae­mon to fetch the cre­den­tial­s, and then, when/if they are there,
one of the sig­nals will be emit­ted, and one of the con­nect­ed meth­ods will be called. This
is nice, be­cause it means you don't have to wor­ry about your app block­ing while Sync­Dae­mon
is do­ing all this.&lt;/p&gt; 
 &lt;p&gt;But what's in those meth­ods we used? Not much, re­al­ly!&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_credentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c"&gt;# Do we have them already? If not, get'em&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;creds_proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_credentials&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c"&gt;# Return what we've got, could be None&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_credentials&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;creds_found&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c"&gt;# Received credentials, save them.&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"creds_found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="c"&gt;# Don't worry about get_quota yet ;-)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_quota_info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_quota&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;creds_not_found&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c"&gt;# No credentials, remove old ones.&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"creds_not_found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;creds_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c"&gt;# No credentials, remove old ones.&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"creds_error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;So, ba­si­cal­ly, self­._­cre­den­tials will hold a set of cre­den­tial­s, or None. Con­grat­u­la­tion­s, we
are now logged in­to Ubun­tu One, so to speak.&lt;/p&gt; 
 &lt;p&gt;So, let's do some­thing use­ful! How about ask­ing for how much free space there is in­
the ac­coun­t? For that, we can't use the lo­cal APIs, we have to con­nect to the server­s, who
are, af­ter al­l, the ones who de­cide if you are over quo­ta or not.&lt;/p&gt; 
 &lt;p&gt;Ac­cess is con­trolled via OAuth. So, to ac­cess the API, we need to sign our re­quest­s. Here
is how it's done. It's not par­tic­u­lar­ly en­light­en­ing, and I did not write it, I just use it:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sign_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c"&gt;# Without credentials, return unsigned URL&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iri2uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"uri:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"GET"&lt;/span&gt;
    &lt;span class="n"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_credentials&lt;/span&gt;
    &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oauth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OAuthConsumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"consumer_key"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                                   &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"consumer_secret"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oauth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OAuthToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                             &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"token_secret"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_qsl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oauth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OAuthRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_consumer_and_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                                        &lt;span class="n"&gt;http_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                        &lt;span class="n"&gt;http_method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                        &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                        &lt;span class="n"&gt;oauth_consumer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                        &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sig_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oauth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OAuthSignatureMethod_HMAC_SHA1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sign_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sig_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"SIGNED:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_url&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;And how do we ask for the quo­ta us­age? By ac­cess­ing the  &lt;a class="reference external" href="https://one.ubuntu.com/api/quota/"&gt;http­s://one.ubun­tu.­com/api/quo­ta/&lt;/a&gt;  en­try point
with the prop­er au­tho­riza­tion, we would get a JSON dic­tio­nary with to­tal and used space.
­So, here's a sim­ple way to do it:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
    &lt;span class="c"&gt;# This is on __init__&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkAccessManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reply_finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_quota&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;"""Launch quota info request."""&lt;/span&gt;
    &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sign_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QUOTA_API&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUrl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setEncodedUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Again, see how get_quo­ta does­n't  &lt;em&gt;re­turn&lt;/em&gt;  the quo­ta? What hap­pens is that get_quo­ta will
launch a HTTP re­quest to the Ubun­tu One server­s, which will, even­tu­al­ly, re­ply with the da­ta.
Y­ou don't want your app to block while you do that. So, QNet­workAc­cess­Man­ag­er will cal­l
­self.re­ply_fin­ished when it gets the re­spon­se:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reply_finished&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;u'/api/quota/'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;# Handle quota responses&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_quota_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readAll&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"Got quota: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_quota_info&lt;/span&gt;
        &lt;span class="c"&gt;# Again, don't worry about update_menu yet ;-)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_menu&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;What else would be nice to have? How about get­ting a call when­ev­er the sta­tus of sync­dae­mon
changes? For ex­am­ple, when sync is up to date, or when you get dis­con­nect­ed? Again, those are
D­Bus sig­nals we are con­nect­ing in our __init__:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;'com.ubuntuone.SyncDaemon'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'/status'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_iface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dbus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_proxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dbus_interface&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'com.ubuntuone.SyncDaemon.Status'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_iface&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect_to_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;'StatusChanged'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_changed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Get the status as of right now&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_last_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_proxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_status&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;And what's sta­tus_changed?&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;status_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"New status:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_last_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_menu&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The pro­cess_s­ta­tus func­tion is bor­ing code to con­vert the in­fo from
sync­dae­mon's sta­tus in­to a hu­man-read­able thing like "Sync is up­-­to-­date". So we
­s­tore that in self­._last_s­ta­tus and up­date the menu.&lt;/p&gt; 
 &lt;p&gt;What menu? Well, a QSys­tem­Tray­I­con's con­text menu! What you have read are the main pieces
y­ou need to cre­ate some­thing use­ful: a Ubun­tu One tray app you can use in KDE, XFCE or open­box.
Or, if you are on uni­ty and in­stall sni-qt, a Ubun­tu One app in­di­ca­tor!&lt;/p&gt; 
 &lt;div class="figure"&gt;
&lt;img alt="http://ubuntuone.com/7iXTbysoMM9PIUS9Ai4TNn" src="http://ubuntuone.com/7iXTbysoMM9PIUS9Ai4TNn"&gt;
&lt;p class="caption"&gt;My Ubun­tu One in­di­ca­tor in ac­tion.&lt;/p&gt; 
 &lt;/div&gt;
&lt;p&gt;You can find the source code for the whole ex­am­ple
app at my  &lt;a class="reference external" href="https://launchpad.net/u1-toys/"&gt;u1-­toys project in launch­pad&lt;/a&gt;  and
here is  &lt;a class="reference external" href="http://bazaar.launchpad.net/~ralsina/u1-toys/trunk/view/head:/indicator/__main__.py"&gt;the full source code&lt;/a&gt; 
(miss­ing some  &lt;a class="reference external" href="http://bazaar.launchpad.net/~ralsina/u1-toys/trunk/view/head:/indicator/rc_images.py"&gt;icon re­sources&lt;/a&gt;, just get the re­po)&lt;/p&gt; 
 &lt;p&gt;Com­ing soon(ish), more ex­am­ple app­s, and cool things to do with our APIs!&lt;/p&gt;&lt;/div&gt;</description><category>Ubuntu one</category><category>linux</category><category>open source</category><category>programming</category><category>pyqt</category><category>python</category><category>qt</category><guid>http://ralsina.com.ar/weblog/posts/BB1006.html</guid><pubDate>Tue, 13 Mar 2012 02:17:00 GMT</pubDate></item><item><title>PyQt Quickie: command line parsing</title><link>http://ralsina.com.ar/weblog/posts/BB997.html</link><description>&lt;div&gt;&lt;p&gt;So, you are writ­ing a PyQt ap­p, and you want it to sup­port com­mand line ar­gu­ments. So you do some­thing like this:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;opt_parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;opt_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-q"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"quickly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"store_true"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Do it quickly (default=False)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opt_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Or maybe even  &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;QAp­­pli­­ca­­tion([])&lt;/span&gt;&lt;/tt&gt;. Ok, you are do­ing it wrong. And this is wrong in most tu­to­ri­al­s, too. Why? Be­cause Qt (and thus PyQt) sup­ports  &lt;a class="reference external" href="http://developer.qt.nokia.com/doc/qt-4.8/qapplication.html#QApplication"&gt;a bunch of use­ful com­mand line op­tions al­ready&lt;/a&gt;. So if you do it like in the first list­ing, and pass "-style=oxy­gen" or what­ev­er, one of the fol­low­ing will hap­pen.&lt;/p&gt; 
 &lt;ol class="loweralpha simple"&gt;
&lt;li&gt;Opt­Pars­er is go­ing to tell you it's not a valid op­tion and abort&lt;/li&gt; 
 &lt;li&gt;You will ig­nore the op­tion and not do any­thing use­ful with it&lt;/li&gt; 
 &lt;li&gt;You will have your own -style op­tion and do  &lt;em&gt;two&lt;/em&gt;  things with it&lt;/li&gt; 
 &lt;/ol&gt;
&lt;p&gt;All three out­comes are less than ide­al.&lt;/p&gt; 
 &lt;p&gt;The right way to do this is:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;opt_parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;opt_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-q"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"quickly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"store_true"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Do it quickly (default=False)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opt_parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This way, you give PyQt a chance to process the op­tions it rec­og­nizes, and, then, you get to han­dle the rest, be­cause  &lt;tt class="docutils literal"&gt;ap­p.ar­gu­ments()&lt;/tt&gt;  has all Qt op­tions re­moved.&lt;/p&gt; 
 &lt;p&gt;The bad side of this is, you will make  &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--help&lt;/span&gt;&lt;/tt&gt;  slight­ly slow­er, since it will have to build a  &lt;tt class="docutils literal"&gt;QAp­pli­ca­tion&lt;/tt&gt;  to do noth­ing, and you will have un­doc­u­ment­ed op­tion­s. So­lu­tion for both prob­lems left as an ex­er­cise.&lt;/p&gt;&lt;/div&gt;</description><category>kde</category><category>pyqt</category><category>python</category><category>qt</category><guid>http://ralsina.com.ar/weblog/posts/BB997.html</guid><pubDate>Fri, 24 Feb 2012 02:38:00 GMT</pubDate></item><item><title>To write, and to write what.</title><link>http://ralsina.com.ar/weblog/posts/BB993.html</link><description>&lt;div&gt;&lt;p&gt;Some of you may know I have writ­ten about 30% of a book, called "Python No Muerde", avail­able at  &lt;a class="reference external" href="http://nomuerde.netmanagers.com.ar"&gt;http://no­muerde.net­man­ager­s.­com.ar&lt;/a&gt;  (in span­ish on­ly).That book has stag­nat­ed for a long time.&lt;/p&gt; 
 &lt;p&gt;On the oth­er hand, I wrote a very pop­u­lar se­ries of post­s, called PyQt by Ex­am­ple, which has (y­ou guessed it) stag­nat­ed for a long time.&lt;/p&gt; 
 &lt;p&gt;The main prob­lem with the book was that I tried to cov­er way too much ground. When com­plete, it would be a 500 page book, and that would in­volve writ­ing half a dozen ex­am­ple app­s, some of them in ar­eas I am no ex­pert.&lt;/p&gt; 
 &lt;p&gt;The main prob­lem with the post se­ries is that the ex­am­ple is lame (a TO­DO ap­p!) and ex­pand­ing it is bor­ing.&lt;/p&gt; 
 &lt;p&gt;¡So, what bet­ter way to fix both things at on­ce, than to merge them!&lt;/p&gt; 
 &lt;p&gt;I will leave Python No Muerde as it is, and will do a new book, called PyQt No Muerde. It will keep the tone and lan­guage of Python No Muerde, and will even share some chap­ter­s, but will fo­cus on de­vel­op­ing a PyQt app or two, in­stead of the much more am­bi­tious goals of Python No Muerde. It will be about 200 pages.&lt;/p&gt; 
 &lt;p&gt;I have ac­quired per­mis­sion from my su­pe­ri­ors (my wife) to work on this project a cou­ple of hours a day, in the ear­ly morn­ing. So, it may move for­ward, or it may not. This is, as usu­al, an ex­per­i­men­t, not a prom­ise.&lt;/p&gt;&lt;/div&gt;</description><category>programming</category><category>pyqt</category><category>python</category><category>qt</category><guid>http://ralsina.com.ar/weblog/posts/BB993.html</guid><pubDate>Fri, 17 Feb 2012 03:18:00 GMT</pubDate></item><item><title>PyQt Quickie: Don't Get Garbage Collected</title><link>http://ralsina.com.ar/weblog/posts/BB990.html</link><description>&lt;div&gt;&lt;p&gt;There is one area where Qt and Python (and in con­se­quence PyQt) have ma­jor dis­agree­ments. That area is mem­o­ry man­age­men­t.&lt;/p&gt; 
 &lt;p&gt;While Qt has its own mech­a­nisms to han­dle ob­ject al­lo­ca­tion and dis­pos­al (the hi­er­ar­chi­cal QOb­ject trees, smart point­er­s, etc.), PyQt runs on Python, so it has garbage col­lec­tion.&lt;/p&gt; 
 &lt;p&gt;Let's con­sid­er a sim­ple ex­am­ple:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;PyQt4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"The process is done!"&lt;/span&gt;
    &lt;span class="c"&gt;# Quit the app&lt;/span&gt;
    &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QCoreApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;launch_process&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c"&gt;# Do something asynchronously&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QProcess&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bin/sleep 3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# After it finishes, call finished&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QCoreApplication&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
    &lt;span class="c"&gt;# Launch the process&lt;/span&gt;
    &lt;span class="n"&gt;launch_process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exec_&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;If you run this, this is what will hap­pen:&lt;/p&gt; 
 &lt;pre class="literal-block"&gt;
QProcess: Destroyed while process is still running.
The process is done!
&lt;/pre&gt;
&lt;p&gt;Plus, the script nev­er end­s. Fun! The prob­lem is that  &lt;tt class="docutils literal"&gt;proc&lt;/tt&gt;  is be­ing delet­ed at the end of  &lt;tt class="docutils literal"&gt;launch_pro­cess&lt;/tt&gt;  be­cause there are no more ref­er­ences to it.&lt;/p&gt; 
 &lt;p&gt;Here is a bet­ter way to do it:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;PyQt4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;

&lt;span class="n"&gt;processes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"The process is done!"&lt;/span&gt;
    &lt;span class="c"&gt;# Quit the app&lt;/span&gt;
    &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QCoreApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;launch_process&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c"&gt;# Do something asynchronously&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QProcess&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;processes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bin/sleep 3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# After it finishes, call finished&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QCoreApplication&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
    &lt;span class="c"&gt;# Launch the process&lt;/span&gt;
    &lt;span class="n"&gt;launch_process&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exec_&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here, we add a glob­al  &lt;tt class="docutils literal"&gt;pro­cess­es&lt;/tt&gt;  set and add  &lt;tt class="docutils literal"&gt;proc&lt;/tt&gt;  there so we al­ways keep a ref­er­ence to it. Now, the pro­gram works as in­tend­ed. How­ev­er, it still has an is­sue: we are leak­ing  &lt;tt class="docutils literal"&gt;QPro­cess&lt;/tt&gt;  ob­ject­s.&lt;/p&gt; 
 &lt;p&gt;While in this case the leak is very short­-lived, since we are end­ing the pro­gram right af­ter the process end­s, in a re­al pro­gram this is not a good idea.&lt;/p&gt; 
 &lt;p&gt;So, we would need to add a way to re­move  &lt;tt class="docutils literal"&gt;proc&lt;/tt&gt;  from  &lt;tt class="docutils literal"&gt;pro­cess­es&lt;/tt&gt;  in  &lt;tt class="docutils literal"&gt;fin­ished&lt;/tt&gt;. This is not as easy as it may seem. Here is an idea that will not work as you ex­pec­t:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;launch_process&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c"&gt;# Do something asynchronously&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QProcess&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;processes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/bin/sleep 3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# Remove the process from the global set when done&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;processes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c"&gt;# After it finishes, call finished&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;In this ver­sion, we will still leak  &lt;tt class="docutils literal"&gt;proc&lt;/tt&gt;, even though  &lt;tt class="docutils literal"&gt;pro­cess­es&lt;/tt&gt;  is emp­ty! Why? Be­cause we are keep­ing a ref­er­ence to  &lt;tt class="docutils literal"&gt;proc&lt;/tt&gt;  in the  &lt;tt class="docutils literal"&gt;lamb­da&lt;/tt&gt;!&lt;/p&gt; 
 &lt;p&gt;I don't re­al­ly have a good an­swer for that that does­n't in­volve turn­ing ev­ery­thing in­to mem­bers of a  &lt;tt class="docutils literal"&gt;QOb­ject&lt;/tt&gt;  and us­ing  &lt;tt class="docutils literal"&gt;sender&lt;/tt&gt;  to fig­ure out what process is end­ing, or us­ing  &lt;tt class="docutils literal"&gt;QSig­nalMap­per&lt;/tt&gt;. That ver­sion is left as an ex­er­cise.&lt;/p&gt;&lt;/div&gt;</description><category>pyqt</category><category>python</category><category>qt</category><guid>http://ralsina.com.ar/weblog/posts/BB990.html</guid><pubDate>Fri, 10 Feb 2012 22:57:00 GMT</pubDate></item><item><title>People doing useful stuff with my toys</title><link>http://ralsina.com.ar/weblog/posts/BB977.html</link><description>&lt;div&gt;&lt;p&gt;About a year ago, I wrote a small web browser, called  &lt;a class="reference external" href="http://devicenzo.googlecode.com"&gt;De Vi­cen­zo&lt;/a&gt;  just for fun.&lt;/p&gt; 
 &lt;p&gt;But hey, some­one went and madeit use­ful for some­thing! Specif­i­cal­ly, to pro­vide  &lt;a class="reference external" href="http://pymolurus.blogspot.com/2012/01/documentation-viewer-for-sphinx.html"&gt;pre­views when do­ing sphix docs&lt;/a&gt;&lt;/p&gt; 
 &lt;p&gt;That's cool :)&lt;/p&gt;&lt;/div&gt;</description><category>pyqt</category><category>python</category><category>qt</category><guid>http://ralsina.com.ar/weblog/posts/BB977.html</guid><pubDate>Wed, 25 Jan 2012 10:33:00 GMT</pubDate></item><item><title>Shipping your PyQt app for windows</title><link>http://ralsina.com.ar/weblog/posts/BB955.html</link><description>&lt;div&gt;&lt;p&gt;I have writ­ten about this in the past, with the gen­er­al con­clu­sion be­ing "it's a pain in the as­s".&lt;/p&gt; 
 &lt;p&gt;So, now, here is how it's done.&lt;/p&gt; 
 &lt;ol class="arabic simple"&gt;
&lt;li&gt;Start with a work­ing PyQt ap­pli­ca­tion. In this ex­am­ple, I will use  &lt;a class="reference external" href="http://code.google.com/p/devicenzo/source/browse/trunk/devicenzo.py"&gt;de­vi­cen­zo.py&lt;/a&gt;  most­ly be­cause:&lt;ol class="loweralpha"&gt; 
 &lt;li&gt;It is a work­ing PyQt ap­­pli­­ca­­tion.&lt;/li&gt;  
  &lt;li&gt;It us­es a big chunk of PyQt&lt;/li&gt;  
  &lt;li&gt;It's easy to test&lt;/li&gt;  
  &lt;/ol&gt; 
 &lt;/li&gt; 
 &lt;li&gt;Now you need a  &lt;tt class="docutils literal"&gt;set­up.py&lt;/tt&gt;. Here's one that work­s, with ex­ten­sive com­m­ments.&lt;/li&gt; 
 &lt;/ol&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="c"&gt;# We will be using py2exe to build the binaries.&lt;/span&gt;
&lt;span class="c"&gt;# You may use other tools, but I know this one.&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;distutils.core&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;py2exe&lt;/span&gt;

&lt;span class="c"&gt;# Now you need to pass arguments to setup&lt;/span&gt;
&lt;span class="c"&gt;# windows is a list of scripts that have their own UI and&lt;/span&gt;
&lt;span class="c"&gt;# thus don't need to run in a console.&lt;/span&gt;

&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;windows&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'devicenzo.py'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="c"&gt;# And now, configure py2exe by passing more options;&lt;/span&gt;

          &lt;span class="s"&gt;'py2exe'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="c"&gt;# This is magic: if you don't add these, your .exe may&lt;/span&gt;
&lt;span class="c"&gt;# or may not work on older/newer versions of windows.&lt;/span&gt;

              &lt;span class="s"&gt;"dll_excludes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                  &lt;span class="s"&gt;"MSVCP90.dll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="s"&gt;"MSWSOCK.dll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="s"&gt;"mswsock.dll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="s"&gt;"powrprof.dll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="p"&gt;],&lt;/span&gt;

&lt;span class="c"&gt;# Py2exe will not figure out that you need these on its own.&lt;/span&gt;
&lt;span class="c"&gt;# You may need one, the other, or both.&lt;/span&gt;

              &lt;span class="s"&gt;'includes'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                  &lt;span class="s"&gt;'sip'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="s"&gt;'PyQt4.QtNetwork'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="p"&gt;],&lt;/span&gt;

&lt;span class="c"&gt;# Optional: make one big exe with everything in it, or&lt;/span&gt;
&lt;span class="c"&gt;# a folder with many things in it. Your choice&lt;/span&gt;
&lt;span class="c"&gt;#             'bundle_files': 1,&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;

&lt;span class="c"&gt;# Qt's dynamically loaded plugins and py2exe really don't&lt;/span&gt;
&lt;span class="c"&gt;# get along.&lt;/span&gt;

&lt;span class="n"&gt;data_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'phonon_backend'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s"&gt;'C:\Python27\Lib\site-packages\PyQt4\plugins\phonon_backend\phonon_ds94.dll'&lt;/span&gt;
                &lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'imageplugins'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s"&gt;'c:\Python27\lib\site-packages\PyQt4\plugins\imageformats\qgif4.dll'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'c:\Python27\lib\site-packages\PyQt4\plugins\imageformats\qjpeg4.dll'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;'c:\Python27\lib\site-packages\PyQt4\plugins\imageformats\qsvg4.dll'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;

&lt;span class="c"&gt;# If you choose the bundle above, you may want to use this, too.&lt;/span&gt;
&lt;span class="c"&gt;#     zipfile=None,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;ol class="arabic simple" start="3"&gt;
&lt;li&gt;Run  &lt;tt class="docutils literal"&gt;python set­up.py py2exe&lt;/tt&gt;  and get a  &lt;tt class="docutils literal"&gt;dist&lt;/tt&gt;  fold­er full of bi­na­ry good­ness.&lt;/li&gt; 
 &lt;/ol&gt;
&lt;p&gt;And that's it. Ex­cept of course, that's  &lt;em&gt;not&lt;/em&gt;  it.&lt;/p&gt; 
 &lt;p&gt;What this will do is cre­ate a bi­na­ry set, ei­ther a fold­er full of things, or a sin­gle EXE file. And that's not enough. You have to con­sid­er at least the fol­low­ing:&lt;/p&gt; 
 &lt;ol class="loweralpha simple"&gt;
&lt;li&gt;Put ev­ery­thing in re­source files: im­ages, qss files, icon­s, etc. Ev­ery file your app need­s? Put it in a re­source file and load it from there. That way you don't have to care about them if you go the "one ex­e" road.&lt;/li&gt; 
 &lt;li&gt;Com­pile .ui files to .py (same rea­son)&lt;/li&gt; 
 &lt;li&gt;Fig­ure out if you use Qt's plu­g­in­s, and make them work. This in­cludes: us­ing Phonon, us­ing Qt­SQL, and us­ing any im­age for­mats oth­er than PNG.&lt;/li&gt; 
 &lt;/ol&gt;
&lt;p&gt;Af­ter you have that, are you done? NO!&lt;/p&gt; 
 &lt;p&gt;Your win­dows us­er will want an in­stall­er. I am not go­ing to go in­to de­tail­s, but I had a good time us­ing Bi­tRock­'s In­stall­Builder for Qt. It's a nice tool, and it work­s. That's a lot in this field.&lt;/p&gt; 
 &lt;p&gt;But is that al­l? NO!&lt;/p&gt; 
 &lt;p&gt;You have to take care of the Vis­ual Stu­dio Run­time. My sug­ges­tion? Get a copy of the 1.1MB vcre­dis­t_x86.exe (not the larg­er one, the 1.1MB one), and ei­ther tell peo­ple to in­stall it man­u­al­ly, or add it to your
in­staller. You are legal­ly al­lowed (AFAIK) to re­dis­tribute that thing as a whole. But not what's in it (un­less you have a VS li­cense).&lt;/p&gt; 
 &lt;p&gt;And we are done? NO!&lt;/p&gt; 
 &lt;p&gt;Once you run your app "in­stalled", if it ev­er prints any­thing to stder­r, you will get ei­ther a di­a­log telling you it did, or worse (if you are in ay­thing new­er than XP), a di­a­log telling you it can't write to a log file, and the app will nev­er work again.&lt;/p&gt; 
 &lt;p&gt;This is be­cause py2exe catch­es stderr and tries to save it on a log­file. Which it tries to cre­ate in the same fold­er as the bi­na­ry. Which is usu­al­ly not al­lowed be­cause of per­mis­sion­s.&lt;/p&gt; 
 &lt;p&gt;So­lu­tion? Your app should nev­er write to stder­r. Write an ex­cepthook and catch that. And then re­move stderr or re­place it with a log file, or some­thing. Just don't let py2exe do it, be­cause the way py2exe does it is bro­ken.&lt;/p&gt; 
 &lt;p&gt;And is that it?&lt;/p&gt; 
 &lt;p&gt;Well, ba­si­cal­ly yes. Of course you should get 4 or 5 dif­fer­ent ver­sions of win­dows to test it on, but you are pret­ty much free to ship your app as you wish. Oh, mind you, don't up­load it to down­load­s.­com be­cause they will wrap your in­stall­er in a larg­er one that in­stalls bloat­ware and crap.&lt;/p&gt; 
 &lt;p&gt;So, there you go.&lt;/p&gt;&lt;/div&gt;</description><category>kde</category><category>programming</category><category>pyqt</category><category>pyqtbyexample</category><category>python</category><category>qt</category><guid>http://ralsina.com.ar/weblog/posts/BB955.html</guid><pubDate>Sun, 24 Jul 2011 21:20:00 GMT</pubDate></item><item><title>New golfing challenge: PatoCabrera</title><link>http://ralsina.com.ar/weblog/posts/BB951.html</link><description>&lt;div&gt;&lt;p&gt;In the spir­it of the  &lt;a class="reference external" href="http://devicenzo.googlecode.com"&gt;De Vi­cen­zo&lt;/a&gt;  web browser, I am start­ing a new pro­gram, called Pa­to Cabr­era. Here are the rules:&lt;/p&gt; 
 &lt;ul class="simple"&gt;
&lt;li&gt;Twit­ter client (no iden­ti.­ca in the first ver­sion, but to be added lat­er)&lt;/li&gt; 
 &lt;li&gt;Has these fea­tures:  &lt;a class="reference external" href="http://pastebin.lugmen.org.ar/6464"&gt;http://­paste­bin.lug­men.org.ar/6464&lt;/a&gt;&lt;/li&gt; 
 &lt;li&gt;Has to be im­ple­ment­ed be­fore April 4th&lt;/li&gt; 
 &lt;li&gt;Small­er than 16384 bytes (of python code) but may be larg­er be­cause of art­work.&lt;/li&gt; 
 &lt;/ul&gt;
&lt;p&gt;Let's see how it works :-)&lt;/p&gt;&lt;/div&gt;</description><category>nerdness</category><category>open source</category><category>programming</category><category>pyqt</category><category>python</category><category>qt</category><guid>http://ralsina.com.ar/weblog/posts/BB951.html</guid><pubDate>Fri, 11 Mar 2011 01:47:00 GMT</pubDate></item><item><title>OK, so THAT is how much browser I can put in 128 lines of code.</title><link>http://ralsina.com.ar/weblog/posts/BB950.html</link><description>&lt;div&gt;&lt;p&gt;I have al­ready post­ed a cou­ple of times (&lt;a class="reference external" href="http://lateral.netmanagers.com.ar/weblog/posts/BB948.html"&gt;1&lt;/a&gt;,  &lt;a class="reference external" href="http://lateral.netmanagers.com.ar/weblog/posts/BB949.html"&gt;2&lt;/a&gt;) about  &lt;a class="reference external" href="http://devicenzo.googlecode.com"&gt;De Vi­cen­zo&lt;/a&gt;  , an at­tempt to im­ple­ment  &lt;em&gt;the rest&lt;/em&gt;  of the browser, start­ing with PyQt's We­bKit... lim­it­ing my­self to 128 lines of code.&lt;/p&gt; 
 &lt;p&gt;Of course I could do more, but I have my stan­dard­s!&lt;/p&gt; 
 &lt;ul class="simple"&gt;
&lt;li&gt;No us­ing  &lt;tt class="docutils literal"&gt;;&lt;/tt&gt;&lt;/li&gt; 
 &lt;li&gt;No  &lt;tt class="docutils literal"&gt;if what­ev­er: f()&lt;/tt&gt;&lt;/li&gt; 
 &lt;/ul&gt;
&lt;p&gt;Oth­er than that, I did a lot of dirty trick­s, but right now, it's a fair­ly com­plete browser, and it has 127 lines of code (ac­cord­ing to sloc­coun­t) so that's enough play­ing and it's time to go back to re­al work.&lt;/p&gt; 
 &lt;p&gt;But first, let's con­sid­er how some fea­tures were im­ple­ment­ed (I'll wrap the lines so they page stays rea­son­ably nar­row), and al­so look at the "nor­mal" ver­sions of the same (the "nor­mal" code is not test­ed, please tell me if it's bro­ken ;-).&lt;/p&gt; 
 &lt;p&gt;This is not some­thing you should learn how to do. In fac­t, this is al­most a trea­tise on how  &lt;em&gt;not&lt;/em&gt;  to do things. This is some of the least python­ic, less clear code you will see this week.&lt;/p&gt; 
 &lt;p&gt;It is short, and it is ex­pres­sive. But it is ug­ly.&lt;/p&gt; 
 &lt;p&gt;I'll dis­cuss  &lt;a class="reference external" href="http://code.google.com/p/devicenzo/source/browse/trunk/devicenzo.py?spec=svn52&amp;amp;r=52"&gt;this ver­sion&lt;/a&gt;.&lt;/p&gt; 
 &lt;div class="section" id="proxy-support"&gt;
&lt;h2&gt;Proxy Support&lt;/h2&gt;
&lt;p&gt;A brows­er is not much of a brows­er if you can't use it with­out a prox­y, but luck­i­ly Qt's net­work stack has good proxy sup­port. The trick was con­fig­ur­ing it.&lt;/p&gt; 
 &lt;p&gt;De Vi­cen­zo sup­ports HTTP and SOCKS prox­ies by pars­ing a  &lt;tt class="docutils literal"&gt;http_proxy&lt;/tt&gt;  en­vi­ron­ment vari­able and set­ting Qt's ap­pli­ca­tion-wide prox­y:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
 &lt;span class="n"&gt;proxy_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'http_proxy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setApplicationProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;\
 &lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpProxy&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'http'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;\
 &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Socks5Proxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;\
 &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;\
&lt;span class="s"&gt;'http_proxy'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;How would that look in nor­mal code?&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;'http_proxy'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;proxy_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'http_proxy'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;starstswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'http'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpProxy&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Socks5Proxy&lt;/span&gt;
    &lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkProxy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setApplicationProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkProxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;proxy_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;As you can see, the main abus­es against python here are the use of the ternary op­er­a­tor as a one-­line if (and nest­ing it), and line length.&lt;/p&gt; 
 &lt;/div&gt;
&lt;div class="section" id="persistent-cookies"&gt;
&lt;h2&gt;Persistent Cookies&lt;/h2&gt;
&lt;p&gt;You re­al­ly need this, since you want to stay logged in­to your sites be­tween ses­sion­s. For this, first I need­ed to write some per­sis­tence mech­a­nis­m, and then save/re­store the cook­ies there.&lt;/p&gt; 
 &lt;p&gt;Here's how the per­sis­tence is done (set­tings is a glob­al  &lt;tt class="docutils literal"&gt;QSet­tings&lt;/tt&gt;  in­stance):&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"Persist an object somewhere under a given key"&lt;/span&gt;
    &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"Get the object stored under 'key' in persistent storage, or the default value"&lt;/span&gt;
    &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It's not ter­ri­bly weird code, ex­cept for the use of the ternary op­er­a­tor in the last line. The use of json en­sures that as long as rea­son­able things are per­sist­ed, you will  &lt;tt class="docutils literal"&gt;get&lt;/tt&gt;  them with the same type as you  &lt;tt class="docutils literal"&gt;put&lt;/tt&gt;  them with­out need­ing to con­vert them or call spe­cial meth­od­s.&lt;/p&gt; 
 &lt;p&gt;So, how do you save/re­store the cook­ies? First, you need to ac­cess the
­cook­ie jar. I could­n't find whether there is a glob­al one, or a per-we­b­view one, so I cre­at­ed a  &lt;tt class="docutils literal"&gt;QNet­work­Cook­ie­Jar&lt;/tt&gt;  in  &lt;a class="reference external" href="http://code.google.com/p/devicenzo/source/browse/trunk/devicenzo.py?spec=svn52&amp;amp;r=52#24"&gt;line 24&lt;/a&gt;  and as­sign it to each web page in  &lt;a class="reference external" href="http://code.google.com/p/devicenzo/source/browse/trunk/devicenzo.py?spec=svn52&amp;amp;r=52#107"&gt;line 107&lt;/a&gt;.&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="c"&gt;# Save the cookies, in the window's closeEvent&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cookiejar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toRawForm&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allCookies&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;

&lt;span class="c"&gt;# Restore the cookies, in the window's __init__&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setAllCookies&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkCookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parseCookies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;\
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cookiejar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])])&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here I con­fess I am guilty of us­ing list com­pre­hen­sions when a for loop would have been the cor­rect thing.&lt;/p&gt; 
 &lt;p&gt;I use the same trick when restor­ing the open tab­s, with the added mis­fea­ture of us­ing a list com­pre­hen­sion and throw­ing away the re­sult:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="c"&gt;# get("tabs") is a list of URLs&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addTab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtCore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tabs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="using-properties-and-signals-in-object-creation"&gt;
&lt;h2&gt;Using Properties and Signals in Object Creation&lt;/h2&gt;
&lt;p&gt;This is a fea­ture of re­cent PyQt ver­sion­s: if you pass prop­er­ty names as key­word ar­gu­ments when you cre­ate an ob­jec­t, they are as­signed the val­ue. If you pass a sig­nal as a key­word ar­gu­men­t, they are  &lt;em&gt;con­nect­ed&lt;/em&gt;  to the giv­en val­ue.&lt;/p&gt; 
 &lt;p&gt;This is a re­al­ly great fea­ture that helps you cre­ate clear, lo­cal code, and it's a great thing to have. But if you are writ­ing evil code... well, you can go to hell on a hand­bas­ket us­ing it.&lt;/p&gt; 
 &lt;p&gt;This is all over the place in De Vi­cen­zo, and here's one ex­am­ple (yes, this is one line):&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;QtWebKit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QWebView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loadProgress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;\
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amCurrent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;\
&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loadFinished&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hide&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loadStarted&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;\
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amCurrent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;titleChanged&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;\
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tabs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTabText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tabs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt;\
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setWindowTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amCurrent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Oh, boy, where do I start with this one.&lt;/p&gt; 
 &lt;p&gt;There are  &lt;tt class="docutils literal"&gt;lamb­da&lt;/tt&gt;  ex­pres­sions used to de­fine the call­backs in­-­place in­stead of just con­nect­ing to a re­al func­tion or method.&lt;/p&gt; 
 &lt;p&gt;There are lamb­das that con­tain the ternary op­er­a­tor:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;loadStarted&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;\
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amCurrent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;There are lamb­das that use  &lt;tt class="docutils literal"&gt;or&lt;/tt&gt;  or a tu­ple to trick python in­to do­ing two things in a sin­gle lamb­da!&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;loadProgress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;\
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pbar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amCurrent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;\
&lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;I won't even  &lt;em&gt;try&lt;/em&gt;  to un­tan­gle this for ed­u­ca­tion­al pur­pos­es, but let's just say that line con­tains what should be re­placed by 3 meth­od­s, and should be spread over 6 lines or more.&lt;/p&gt; 
 &lt;/div&gt;
&lt;div class="section" id="download-manager"&gt;
&lt;h2&gt;Download Manager&lt;/h2&gt;
&lt;p&gt;Ok, call­ing it a man­ag­er is over­reach­ing, since you can't stop them once they start, but hey, it lets you down­load things and keep on brows­ing, and re­ports the pro­gress!&lt;/p&gt; 
 &lt;p&gt;First, on  &lt;a class="reference external" href="http://code.google.com/p/devicenzo/source/browse/trunk/devicenzo.py?spec=svn52&amp;amp;r=52#16"&gt;line 16&lt;/a&gt;  I cre­at­ed a  &lt;tt class="docutils literal"&gt;bars&lt;/tt&gt;  dic­tio­nary for gen­er­al book­keep­ing of the down­load­s.&lt;/p&gt; 
 &lt;p&gt;Then, I need­ed to del­e­gate the un­sup­port­ed con­tent to the right method, and that's done in  &lt;a class="reference external" href="http://code.google.com/p/devicenzo/source/browse/trunk/devicenzo.py?spec=svn52&amp;amp;r=52#108"&gt;lines 108 and 109&lt;/a&gt;&lt;/p&gt; 
 &lt;p&gt;What that does is ba­si­cal­ly that when­ev­er you click on some­thing We­bKit can't han­dle, the method  &lt;tt class="docutils literal"&gt;fetch&lt;/tt&gt;  will be called and passed the net­work re­quest.&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtGui&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QFileDialog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getSaveFileName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; \
        &lt;span class="s"&gt;"Save File"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expanduser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'~'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;\
            &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtGui&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QProgressBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'%p% - '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;statusBar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addPermanentWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downloadProgress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;\
            &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;No re­al code golf­ing here, ex­cept for long lines, but once you break them rea­son­ably, this is pret­ty much the ob­vi­ous way to do it:&lt;/p&gt; 
 &lt;ul class="simple"&gt;
&lt;li&gt;Ask for a file­name&lt;/li&gt; 
 &lt;li&gt;Cre­ate a pro­gress­bar, put it in the sta­tus­bar, and con­nect it to the
­down­load­'s progress sig­nal­s.&lt;/li&gt; 
 &lt;/ul&gt;
&lt;p&gt;Then, of course, we need ths  &lt;tt class="docutils literal"&gt;progress&lt;/tt&gt;  slot, that up­dates the pro­gress­bar:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;received&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;\
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;\
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;100.&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;received&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Yes, I de­fined a method as a lamb­da to save 1 line. [facepalm]&lt;/p&gt; 
 &lt;p&gt;And the  &lt;tt class="docutils literal"&gt;fin­ished&lt;/tt&gt;  slot for when the down­load is done:&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;finished&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;redirURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtNetwork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QNetworkRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;\
        &lt;span class="n"&gt;RedirectionTargetAttribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteLater&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;redirURL&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;redirURL&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redirURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'wb'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readAll&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;No­tice that it even han­dles redi­rec­tions sane­ly! Be­yond that, it just hides the progress bar, saves the data, end of sto­ry. The long­est line is not even my fault!&lt;/p&gt; 
 &lt;p&gt;There is a big in­ef­fi­cien­cy in that the whole file is kept in mem­o­ry un­til the end. If you down­load a DVD im­age, that's gonna sting.&lt;/p&gt; 
 &lt;p&gt;Al­so, us­ing  &lt;tt class="docutils literal"&gt;with&lt;/tt&gt;  saves a line and does­n't leak a file han­dle, com­pared to the al­ter­na­tives.&lt;/p&gt; 
 &lt;/div&gt;
&lt;div class="section" id="printing"&gt;
&lt;h2&gt;Printing&lt;/h2&gt;
&lt;p&gt;Again Qt saved me, be­cause do­ing this man­u­al­ly would have been a pain. How­ev­er, it turns out that print­ing is just ... there? Qt, spe­cial­ly when used via PyQt is such an  &lt;em&gt;awe­some­ly&lt;/em&gt;  rich en­vi­ron­men­t.&lt;/p&gt; 
 &lt;pre class="code python literal-block"&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;previewer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtGui&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QPrintPreviewDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;\
    &lt;span class="n"&gt;paintRequested&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;do_print&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QtGui&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QShortcut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ctrl+p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;\
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;previewer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exec_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;There's not even any need to golf here, that's ex­act­ly as much code as you need to hook Ctr­l+p to make a  &lt;tt class="docutils literal"&gt;QWe­b­View&lt;/tt&gt;  print.&lt;/p&gt; 
 &lt;/div&gt;
&lt;div class="section" id="other-tricks"&gt;
&lt;h2&gt;Other Tricks&lt;/h2&gt;
&lt;p&gt;There are no oth­er trick­s. All that's left is cre­at­ing wid­get­s, con­nect­ing things to one an­oth­er, and en­joy­ing the awe­some ex­pe­ri­ence of pro­gram­ming PyQt, where you can write a whole web brows­er (ex­cept the en­gine) in 127 lines of code.&lt;/p&gt; 
 &lt;/div&gt;&lt;/div&gt;</description><category>open source</category><category>programming</category><category>pyqt</category><category>python</category><category>qt</category><guid>http://ralsina.com.ar/weblog/posts/BB950.html</guid><pubDate>Tue, 08 Mar 2011 21:45:00 GMT</pubDate></item></channel></rss>