tag:blogger.com,1999:blog-54242523645347233002024-09-01T10:06:41.871-05:00Feihong HsuFeihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.comBlogger10125tag:blogger.com,1999:blog-5424252364534723300.post-22820231327143612002008-02-18T11:39:00.001-06:002008-02-18T11:53:55.893-06:00Free Web Hosting<div class="document">
<p>Recently I researched the state of free web hosting. I came away pretty surprised at my findings. In the past, setting up a decent website without spending a cent was impossible. But now, it's not only possible, it's easy to create a <em>very nice</em> site using only free tools. Below is my highly-opinionated guide on the best free services.</p>
<div class="section">
<h1><a name="web-site">Web Site</a></h1>
<p>First of all, you need a place to store and manage your pages. There are so many choices in this area that I couldn't even begin to sort through them all. However, two sites that stood out to me were <a class="reference" href="http://pages.google.com/">Google Page Creator</a> and <a class="reference" href="http://wordpress.com">WordPress.Com</a>.</p>
<p>Google Page Creator allows up to 100 MB of storage for pages and any attachments you might want to upload. Pages created through their web interface tend to look kind of weird, but you can create pages on your own computer and upload them. Unlike many other services, there doesn't seem to be any restrictions on the types of files that you can upload to Google Page Creator.</p>
<p>WordPress.Com is mainly a blogging site, but it has a feature called Pages that lets you create non-blog pages and edit them using HTML. You don't have a lot of flexibility in the design of your pages, since the pages get displayed using the same template used for your blog. But you get an unlimited number of pages, and you get a very generous allotment of 3 GB for image and document uploads (other files are not allowed unless you upgrade to the paid service).</p>
<p>Neither service has an API, which is disappointing. WordPress.Com does give you something they call an API key, but it's only for use with the Akismet spam filtering service.</p>
<p>I should mention that there are various hosted wiki services that you can use to build a web site, but I won't get into that in this post.</p>
</div>
<div class="section">
<h1><a name="blog">Blog</a></h1>
<p>I have the most experience with <a class="reference" href="http://blogger.com">Blogger</a>, so I can't help but put that as my number one recommendation. One of the reasons that I chose Blogger was that it has a solid and well-documented API. I don't think the other free blogging services are quite as good in this area. Using the API, I can easily create and update all my blog posts on my own machine and then upload them to Blogger's servers at my leisure. Another advantage is that no ads ever appear on your blog (unless you want them to).</p>
</div>
<div class="section">
<h1><a name="images">Images</a></h1>
<p><a class="reference" href="http://picasaweb.google.com">Picasa</a> is my number one pick here, but <a class="reference" href="http://flickr.com">Flickr</a> seems nice too. I like Picasa the best because it has an API similar to the Blogger API <a class="footnote-reference" href="#id3-47b9c632" name="id1-47b9c632">[1]</a>. If I used Flickr, I'd have to learn a whole different API, which would be annoying. Picasa gives you 1 GB of storage, which I think is pretty decent. Some of the documentation claims that Picasa only supports JPEG images, but that seems to be out-of-date because I've uploaded PNG files without any issue (and they were not converted to JPEGs during the upload process).</p>
</div>
<div class="section">
<h1><a name="videos">Videos</a></h1>
<p>Well, <a class="reference" href="http://youtube.com">YouTube</a> pretty much has this market cornered. Unless you have some specific needs for video hosting, it's best to go with YouTube. Since YouTube is owned by Google, you get a nice API for it as well. The YouTube API does not support uploading, but I don't think that's a big deal.</p>
</div>
<div class="section">
<h1><a name="rich-text-documents-and-spreadsheets">Rich Text Documents and Spreadsheets</a></h1>
<p>I don't have any experience with it but it seems that <a class="reference" href="http://docs.google.com">Google Docs</a> is the best choice in this area. The limits for the service are kind of complicated so I won't summarize them here but you can <a class="reference" href="http://documents.google.com/support/bin/answer.py?answer=37603&topic=8613">read them for yourself</a>.</p>
</div>
<div class="section">
<h1><a name="presentations">Presentations</a></h1>
<p>Google Docs allows you to publish presentations as well, but there's also <a class="reference" href="http://slideshare.net">SlideShare</a>, which also offers an API. From reading the online documentation, I think SlideShare edges out Google Docs because it allows you to import from PowerPoint, OpenOffice, and PDF, while Google Docs only allows you to import from PowerPoint. Also, SlideShare allows presentations up to 30 MB, while Google Docs only gives you up to 10 MB.</p>
</div>
<div class="section">
<h1><a name="miscellaneous-documents">Miscellaneous Documents</a></h1>
<p>I don't have a lot of experience with it yet, but <a class="reference" href="http://base.google.com">Google Base</a> seems to be a good choice for hosting documents in various formats. Basically, you can create an item on Google Base and attach different kinds of files to it. You can attach the following formats: Adobe PDF (.pdf), Microsoft Word (.doc), Microsoft PowerPoint (.ppt), Microsoft Excel (.xls), Text (.txt), HTML (.html), Rich Text Format (.rtf), ASCII, Unicode, XML, and Word Perfect documents (.wpd). Be careful, though: depending on the type of item you create, it may expire after a certain amount of time. And of course Google Base offers an API.</p>
</div>
<div class="section">
<h1><a name="general-file-hosting">General File Hosting</a></h1>
<p>For all your other file hosting needs, I recommend <a class="reference" href="http://divshare.com">DivShare</a>. This free service gives you 5 GB of disk space along with 50 GB of bandwidth, which I think is kind of amazing. It doesn't restrict the types of files you can upload, so this is the place to host your ZIP, EXE, TAR.GZ, and BZ2 files. One added benefit is that it treats media files specially. For example, you can use DivShare to embed an audio file directly into your web page. That means someone viewing your page can play a song from your page without needing to download it first. I personally don't see myself ever using this feature, but it is nifty. Even though there are plenty of other ad-supported file hosting services, DivShare is a cut above the rest because it has an API that supports uploading.</p>
</div>
<div class="section">
<h1><a name="conclusion">Conclusion</a></h1>
<p>Besides the services I wrote about in this post, there are also hosted wikis and mashup creators, both of which are loaded topics, and no way am I going to try tackling them in this already-too-long post.</p>
<p>I think I've convincingly argued that you can create a fairly sophisticated web site using only free tools. Many of the best services out there offer APIs, meaning that if you're a programmer, you can combine them together to create your own custom web publishing solution. In a lot of cases, it may actually be preferable to publish your material on hosted services rather than affordable web hosts like <a class="reference" href="http://dreamhost.com">DreamHost</a> or <a class="reference" href="http://webfaction.com">WebFaction</a> <a class="footnote-reference" href="#id4-47b9c632" name="id2-47b9c632">[2]</a>. That's because these hosted services are run by organizations with a lot of resources at their disposal; by using them you don't have to worry about bandwidth allocations, outages, backups, spam filtering, comment moderation, and all those other annoying issues that keep you from Getting Things Done.</p>
<table class="docutils footnote" frame="void" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1-47b9c632" name="id3-47b9c632">[1]</a></td><td>Picasa and Blogger both use the Atom publication protocol. And since I'm a Python developer, I can use the same <tt class="docutils literal"><span class="pre">gdata</span></tt> module to access both services.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id2-47b9c632" name="id4-47b9c632">[2]</a></td><td>I should mention that I'm a satisfied customer of both DreamHost and WebFaction. But after doing all this research, I think that the only thing I'll be hosting on them will be my own custom-built web applications.</td></tr>
</tbody>
</table>
</div>
</div>
<div class="source" style="display:none"><pre>.. editlink:: /feeds/5424252364534723300/posts/default/2282023132714361200
Free Web Hosting
================
.. labels:: web hosting, file hosting
Recently I researched the state of free web hosting. I came away pretty surprised at my findings. In the past, setting up a decent website without spending a cent was impossible. But now, it's not only possible, it's easy to create a *very nice* site using only free tools. Below is my highly-opinionated guide on the best free services.
Web Site
--------
First of all, you need a place to store and manage your pages. There are so many choices in this area that I couldn't even begin to sort through them all. However, two sites that stood out to me were `Google Page Creator`_ and WordPress.Com_.
.. _Google Page Creator: http://pages.google.com/
.. _WordPress.Com: http://wordpress.com
Google Page Creator allows up to 100 MB of storage for pages and any attachments you might want to upload. Pages created through their web interface tend to look kind of weird, but you can create pages on your own computer and upload them. Unlike many other services, there doesn't seem to be any restrictions on the types of files that you can upload to Google Page Creator.
WordPress.Com is mainly a blogging site, but it has a feature called Pages that lets you create non-blog pages and edit them using HTML. You don't have a lot of flexibility in the design of your pages, since the pages get displayed using the same template used for your blog. But you get an unlimited number of pages, and you get a very generous allotment of 3 GB for image and document uploads (other files are not allowed unless you upgrade to the paid service).
Neither service has an API, which is disappointing. WordPress.Com does give you something they call an API key, but it's only for use with the Akismet spam filtering service.
I should mention that there are various hosted wiki services that you can use to build a web site, but I won't get into that in this post.
Blog
----
I have the most experience with Blogger_, so I can't help but put that as my number one recommendation. One of the reasons that I chose Blogger was that it has a solid and well-documented API. I don't think the other free blogging services are quite as good in this area. Using the API, I can easily create and update all my blog posts on my own machine and then upload them to Blogger's servers at my leisure. Another advantage is that no ads ever appear on your blog (unless you want them to).
.. _Blogger: http://blogger.com
Images
------
Picasa_ is my number one pick here, but Flickr_ seems nice too. I like Picasa the best because it has an API similar to the Blogger API [#]_. If I used Flickr, I'd have to learn a whole different API, which would be annoying. Picasa gives you 1 GB of storage, which I think is pretty decent. Some of the documentation claims that Picasa only supports JPEG images, but that seems to be out-of-date because I've uploaded PNG files without any issue (and they were not converted to JPEGs during the upload process).
.. _Picasa: http://picasaweb.google.com
.. _Flickr: http://flickr.com
Videos
------
Well, YouTube_ pretty much has this market cornered. Unless you have some specific needs for video hosting, it's best to go with YouTube. Since YouTube is owned by Google, you get a nice API for it as well. The YouTube API does not support uploading, but I don't think that's a big deal.
.. _YouTube: http://youtube.com
Rich Text Documents and Spreadsheets
------------------------------------
I don't have any experience with it but it seems that `Google Docs`_ is the best choice in this area. The limits for the service are kind of complicated so I won't summarize them here but you can `read them for yourself`_.
.. _Google Docs: http://docs.google.com
.. _read them for yourself: http://documents.google.com/support/bin/answer.py?answer=37603&topic=8613
Presentations
-------------
Google Docs allows you to publish presentations as well, but there's also SlideShare_, which also offers an API. From reading the online documentation, I think SlideShare edges out Google Docs because it allows you to import from PowerPoint, OpenOffice, and PDF, while Google Docs only allows you to import from PowerPoint. Also, SlideShare allows presentations up to 30 MB, while Google Docs only gives you up to 10 MB.
.. _SlideShare: http://slideshare.net
Miscellaneous Documents
-----------------------
I don't have a lot of experience with it yet, but `Google Base`_ seems to be a good choice for hosting documents in various formats. Basically, you can create an item on Google Base and attach different kinds of files to it. You can attach the following formats: Adobe PDF (.pdf), Microsoft Word (.doc), Microsoft PowerPoint (.ppt), Microsoft Excel (.xls), Text (.txt), HTML (.html), Rich Text Format (.rtf), ASCII, Unicode, XML, and Word Perfect documents (.wpd). Be careful, though: depending on the type of item you create, it may expire after a certain amount of time. And of course Google Base offers an API.
.. _Google Base: http://base.google.com
General File Hosting
--------------------
For all your other file hosting needs, I recommend DivShare_. This free service gives you 5 GB of disk space along with 50 GB of bandwidth, which I think is kind of amazing. It doesn't restrict the types of files you can upload, so this is the place to host your ZIP, EXE, TAR.GZ, and BZ2 files. One added benefit is that it treats media files specially. For example, you can use DivShare to embed an audio file directly into your web page. That means someone viewing your page can play a song from your page without needing to download it first. I personally don't see myself ever using this feature, but it is nifty. Even though there are plenty of other ad-supported file hosting services, DivShare is a cut above the rest because it has an API that supports uploading.
.. _DivShare: http://divshare.com
Conclusion
----------
Besides the services I wrote about in this post, there are also hosted wikis and mashup creators, both of which are loaded topics, and no way am I going to try tackling them in this already-too-long post.
I think I've convincingly argued that you can create a fairly sophisticated web site using only free tools. Many of the best services out there offer APIs, meaning that if you're a programmer, you can combine them together to create your own custom web publishing solution. In a lot of cases, it may actually be preferable to publish your material on hosted services rather than affordable web hosts like DreamHost_ or WebFaction_ [#]_. That's because these hosted services are run by organizations with a lot of resources at their disposal; by using them you don't have to worry about bandwidth allocations, outages, backups, spam filtering, comment moderation, and all those other annoying issues that keep you from Getting Things Done.
.. _DreamHost: http://dreamhost.com
.. _WebFaction: http://webfaction.com
.. [#] Picasa and Blogger both use the Atom publication protocol. And since I'm a Python developer, I can use the same ``gdata`` module to access both services.
.. [#] I should mention that I'm a satisfied customer of both DreamHost and WebFaction. But after doing all this research, I think that the only thing I'll be hosting on them will be my own custom-built web applications.
</pre></div>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-2603038441945526882008-02-16T08:25:00.001-06:002008-02-17T09:29:36.667-06:00XPath: Getting All the Descendant Nodes<div class="document">
<p>For some reason I can never remember the proper XPath for getting all the descendant nodes (both element and text nodes). I figure if I post it on my blog, I can just look it up whenever I forget (or maybe writing it down will force it permanently into my brain). Here's the XPath expression:</p>
<pre class="literal-block">
//*|//text()
</pre>
<p>Pretty simple, huh? At first, I thought it was <tt class="docutils literal"><span class="pre">//*|text()</span></tt>, but that doesn't actually work. Neither does <tt class="docutils literal"><span class="pre">//text()|*</span></tt>. Those two XPath expressions aren't even equivalent -- they actually give you different results.</p>
<p>Now for an example! Let's say that you have the following XML:</p>
<div class="highlight"><pre><span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"><title></span>Converting from Local Time to UTC<span class="nt"></title></span>
<span class="nt"><link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"../preview.css"</span> <span class="na">type=</span><span class="s">"text/css"</span> <span class="nt">/></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><div</span> <span class="na">id=</span><span class="s">"meta"</span><span class="nt">></span>
<span class="nt"><table></span>
<span class="nt"><tr></span>
<span class="nt"><td><b></span>Title:<span class="nt"></b></td></span>
<span class="nt"><td></span>Converting from Local Time to UTC<span class="nt"></td></span>
<span class="nt"></tr></span>
<span class="nt"><tr></span>
<span class="nt"><td><b></span>Entry Id:<span class="nt"></b></td></span>
<span class="nt"><td></span>None<span class="nt"></td></span>
<span class="nt"></tr></span>
<span class="nt"><tr></span>
<span class="nt"><td><b></span>Labels:<span class="nt"></b></td></span>
<span class="nt"><td></span>python, utc, datetime<span class="nt"></td></span>
<span class="nt"></tr></span>
<span class="nt"></table></span>
<span class="nt"></div></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</pre></div>
<p>Using Python's <a class="reference" href="http://codespeak.net/lxml/">lxml</a> module, we can write a short script that prints out all the element tags and non-whitespace strings:</p>
<div class="highlight"><pre><span class="k">from</span> <span class="nn">lxml</span> <span class="k">import</span> <span class="n">etree</span>
<span class="n">tree</span> <span class="o">=</span> <span class="n">etree</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="s">'temp.xml'</span><span class="p">))</span>
<span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">tree</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s">'//*|//text()'</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="nb">basestring</span><span class="p">):</span>
<span class="k">if</span> <span class="n">node</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
<span class="k">print</span> <span class="nb">repr</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span> <span class="s">'<</span><span class="si">%s</span><span class="s">>'</span> <span class="o">%</span> <span class="n">node</span><span class="o">.</span><span class="n">tag</span>
</pre></div>
<p>Running the above code, we get the following output:</p>
<pre class="literal-block">
<html>
<head>
<title>
'Converting from Local Time to UTC'
<link>
<body>
<div>
<table>
<tr>
'Converting from Local Time to UTC'
<tr>
<td>
<b>
<tr>
'Title:'
<td>
<td>
<b>
'Entry Id:'
<td>
'None'
<td>
<b>
'Labels:'
<td>
'python, utc, datetime'
</pre>
<p>As you can see, the XPath expression gives you the element and text nodes in the exact order that they appear in the document.</p>
</div>
<div class="source" style="display:none"><pre>.. editlink:: /feeds/5424252364534723300/posts/default/260303844194552688
XPath: Getting All the Descendant Nodes
=======================================
.. labels:: xpath, xml, python, lxml
For some reason I can never remember the proper XPath for getting all the descendant nodes (both element and text nodes). I figure if I post it on my blog, I can just look it up whenever I forget (or maybe writing it down will force it permanently into my brain). Here's the XPath expression::
//*|//text()
Pretty simple, huh? At first, I thought it was ``//*|text()``, but that doesn't actually work. Neither does ``//text()|*``. Those two XPath expressions aren't even equivalent -- they actually give you different results.
Now for an example! Let's say that you have the following XML:
.. code:: xml
<html>
<head>
<title>Converting from Local Time to UTC</title>
<link rel="stylesheet" href="../preview.css" type="text/css" />
</head>
<body>
<div id="meta">
<table>
<tr>
<td><b>Title:</b></td>
<td>Converting from Local Time to UTC</td>
</tr>
<tr>
<td><b>Entry Id:</b></td>
<td>None</td>
</tr>
<tr>
<td><b>Labels:</b></td>
<td>python, utc, datetime</td>
</tr>
</table>
</div>
</body>
</html>
.. _lxml: http://codespeak.net/lxml/
Using Python's lxml_ module, we can write a short script that prints out all the element tags and non-whitespace strings:
.. code:: python
from lxml import etree
tree = etree.parse(open('temp.xml'))
for node in tree.xpath('//*|//text()'):
if isinstance(node, basestring):
if node.strip():
print repr(node.strip())
else:
print '<%s>' % node.tag
Running the above code, we get the following output::
<html>
<head>
<title>
'Converting from Local Time to UTC'
<link>
<body>
<div>
<table>
<tr>
'Converting from Local Time to UTC'
<tr>
<td>
<b>
<tr>
'Title:'
<td>
<td>
<b>
'Entry Id:'
<td>
'None'
<td>
<b>
'Labels:'
<td>
'python, utc, datetime'
As you can see, the XPath expression gives you the element and text nodes in the exact order that they appear in the document.</pre></div>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-6030693380998117432008-02-15T11:52:00.001-06:002008-02-18T07:25:03.928-06:00Python.NET 2.0 for .NET SP1<div class="document">
<p>In a <a class="reference" href="http://feihonghsu.blogspot.com/2008/02/installing-pythonnet-20-alpha-2-on.html">recent post</a> I showed how to compile and install Python.NET 2.0 alpha 2. Unfortunately, if you are using .NET 2.0 SP 1, the instructions won't produce a fully-functional build <a class="footnote-reference" href="#id3-47b9872e" name="id1-47b9872e">[1]</a>. That's because some changes in SP1 broke the latest Python.NET code. However, Nicolas Lelong figured out the solution and posted a <a class="reference" href="http://mail.python.org/pipermail/pythondotnet/2008-January/000771.html">simple patch</a> to the Python.NET mailing list. The patch is only necessary if you are using .NET 2.0 SP 1, but non-SP 1 systems can use it as well.</p>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">I've recompiled the binaries myself and posted them <a class="reference" href="http://feihong.hsu.googlepages.com/PythonNET2.0.zip">here</a>.</p>
</div>
<p>To verify that the patch works correctly, try running the following code.</p>
<div class="highlight"><pre><span class="k">import</span> <span class="nn">clr</span>
<span class="n">clr</span><span class="o">.</span><span class="n">AddReference</span><span class="p">(</span><span class="s">'System.Windows.Forms'</span><span class="p">)</span>
<span class="k">from</span> <span class="nn">System.Drawing</span> <span class="k">import</span> <span class="n">Color</span>
<span class="k">from</span> <span class="nn">System.Windows.Forms</span> <span class="k">import</span> <span class="n">Form</span><span class="p">,</span> <span class="n">Button</span><span class="p">,</span> <span class="n">Label</span><span class="p">,</span> <span class="n">BorderStyle</span><span class="p">,</span> <span class="n">DockStyle</span>
<span class="n">count</span> <span class="o">=</span> <span class="mf">0</span>
<span class="k">def</span> <span class="nf">onclick</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
<span class="k">global</span> <span class="n">count</span>
<span class="n">count</span> <span class="o">+=</span> <span class="mf">1</span>
<span class="n">l</span><span class="o">.</span><span class="n">Text</span> <span class="o">=</span> <span class="s">'You clicked the {</span><span class="si">%s</span><span class="s">} button </span><span class="si">%d</span><span class="s"> times'</span> <span class="o">%</span> <span class="p">(</span><span class="n">sender</span><span class="o">.</span><span class="n">Text</span><span class="p">,</span> <span class="n">count</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">Form</span><span class="p">()</span>
<span class="n">f</span><span class="o">.</span><span class="n">Text</span> <span class="o">=</span> <span class="s">'Hello WinForms!'</span>
<span class="n">f</span><span class="o">.</span><span class="n">Width</span> <span class="o">=</span> <span class="mf">500</span>
<span class="n">l</span> <span class="o">=</span> <span class="n">Label</span><span class="p">()</span>
<span class="n">l</span><span class="o">.</span><span class="n">Text</span> <span class="o">=</span> <span class="s">'This is a label'</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">Button</span><span class="p">()</span>
<span class="n">b</span><span class="o">.</span><span class="n">Text</span> <span class="o">=</span> <span class="s">'Click Me!'</span>
<span class="n">b</span><span class="o">.</span><span class="n">Click</span> <span class="o">+=</span> <span class="n">onclick</span>
<span class="c"># Layout:</span>
<span class="n">l</span><span class="o">.</span><span class="n">Dock</span> <span class="o">=</span> <span class="n">DockStyle</span><span class="o">.</span><span class="n">Top</span>
<span class="n">b</span><span class="o">.</span><span class="n">Dock</span> <span class="o">=</span> <span class="n">DockStyle</span><span class="o">.</span><span class="n">Top</span>
<span class="n">f</span><span class="o">.</span><span class="n">Controls</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
<span class="n">f</span><span class="o">.</span><span class="n">Controls</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="n">f</span><span class="o">.</span><span class="n">ShowDialog</span><span class="p">()</span>
</pre></div>
<p>If you don't see any weird errors <a class="footnote-reference" href="#id4-47b9872e" name="id2-47b9872e">[2]</a>, then everything should be fine.</p>
<table class="docutils footnote" frame="void" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1-47b9872e" name="id3-47b9872e">[1]</a></td><td>Specifically, delegates won't work. That means, for example, that you won't be able to use Python functions to handle button clicks in a GUI.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id2-47b9872e" name="id4-47b9872e">[2]</a></td><td><p class="first">If you are using an unpatched Python.NET with .NET SP1, you would see an error like this:</p>
<pre class="last literal-block">
System.TypeInitializationException: The type initializer for 'Python.Runtime.CodeGenerator' threw an exception.
</pre>
</td></tr>
</tbody>
</table>
</div>
<div class="source" style="display:none"><pre>.. editlink:: /feeds/5424252364534723300/posts/default/603069338099811743
Python.NET 2.0 for .NET SP1
===========================
.. labels:: python, dotnet, python.net
In a `recent post`_ I showed how to compile and install Python.NET 2.0 alpha 2. Unfortunately, if you are using .NET 2.0 SP 1, the instructions won't produce a fully-functional build [#]_. That's because some changes in SP1 broke the latest Python.NET code. However, Nicolas Lelong figured out the solution and posted a `simple patch`_ to the Python.NET mailing list. The patch is only necessary if you are using .NET 2.0 SP 1, but non-SP 1 systems can use it as well.
.. note::
I've recompiled the binaries myself and posted them here_.
.. _recent post: http://feihonghsu.blogspot.com/2008/02/installing-pythonnet-20-alpha-2-on.html
.. _simple patch: http://mail.python.org/pipermail/pythondotnet/2008-January/000771.html
.. _here: http://feihong.hsu.googlepages.com/PythonNET2.0.zip
To verify that the patch works correctly, try running the following code.
.. code:: python
import clr
clr.AddReference('System.Windows.Forms')
from System.Drawing import Color
from System.Windows.Forms import Form, Button, Label, BorderStyle, DockStyle
count = 0
def onclick(sender, args):
global count
count += 1
l.Text = 'You clicked the {%s} button %d times' % (sender.Text, count)
if __name__ == '__main__':
f = Form()
f.Text = 'Hello WinForms!'
f.Width = 500
l = Label()
l.Text = 'This is a label'
b = Button()
b.Text = 'Click Me!'
b.Click += onclick
# Layout:
l.Dock = DockStyle.Top
b.Dock = DockStyle.Top
f.Controls.Add(l)
f.Controls.Add(b)
f.ShowDialog()
If you don't see any weird errors [#]_, then everything should be fine.
.. [#] Specifically, delegates won't work. That means, for example, that you won't be able to use Python functions to handle button clicks in a GUI.
.. [#] If you are using an unpatched Python.NET with .NET SP1, you would see an error like this:
::
System.TypeInitializationException: The type initializer for 'Python.Runtime.CodeGenerator' threw an exception.
</pre></div>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-61080757310856226502008-02-14T07:15:00.001-06:002008-02-14T07:15:35.897-06:00Broken CSS<div class="document" id="broken-css">
<p>The Blogger template I'm using is called "Minima Lefty Stretch". Out of the many pre-made templates that Blogger offers to you, it seemed to be the one that best fit my needs <a class="footnote-reference" href="#id2" id="id1" name="id1">[1]</a>. One of the cool things about the pre-made templates is that they look very consistent across all the browsers. However, even Blogger (Google) can't get it right all the time.</p>
<p>Shortly after posting my <a class="reference" href="http://feihonghsu.blogspot.com/2008/02/installing-pythonnet-20-alpha-2-on.html">previous entry</a>, I realized that the items in my <tt class="docutils literal"><span class="pre">OL</span></tt> list didn't have numbers when viewed in IE 7. When I checked the page in Firefox, Safari, and Opera, they all looked fine. I do want to get my blog to render correctly in IE, so I guess I'll have to either tweak my existing template or else create a custom one from scratch.</p>
<table class="docutils footnote" frame="void" id="id2" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1" name="id2">[1]</a></td><td>Since this is a blog about programming, I plan on posting a lot of code snippets. These look terrible in the majority of Blogger templates because they get truncated by the width of the main content DIV. Minima Lefty Stretch is one of the few exceptions, since it stretches to match the width of the browser viewport.</td></tr>
</tbody>
</table>
</div>
<div class="source"><pre>Broken CSS
==========
.. labels:: css, blogger template
The Blogger template I'm using is called "Minima Lefty Stretch". Out of the many pre-made templates that Blogger offers to you, it seemed to be the one that best fit my needs [#]_. One of the cool things about the pre-made templates is that they look very consistent across all the browsers. However, even Blogger (Google) can't get it right all the time.
Shortly after posting my `previous entry`_, I realized that the items in my ``OL`` list didn't have numbers when viewed in IE 7. When I checked the page in Firefox, Safari, and Opera, they all looked fine. I do want to get my blog to render correctly in IE, so I guess I'll have to either tweak my existing template or else create a custom one from scratch.
.. _previous entry: http://feihonghsu.blogspot.com/2008/02/installing-pythonnet-20-alpha-2-on.html
.. [#] Since this is a blog about programming, I plan on posting a lot of code snippets. These look terrible in the majority of Blogger templates because they get truncated by the width of the main content DIV. Minima Lefty Stretch is one of the few exceptions, since it stretches to match the width of the browser viewport.</pre></div>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-78847673665053089622008-02-13T07:27:00.001-06:002008-02-15T10:54:09.395-06:00Installing Python.NET 2.0 Alpha 2 on Windows XP<div class="document" id="installing-python-net-2-0-alpha-2-on-windows-xp">
<p><a class="reference" href="http://pythonnet.sourceforge.net">Python.NET</a> is a project that lets you use .NET libraries from within Python <a class="footnote-reference" href="#id6" id="id1" name="id1">[1]</a>. The latest version (2.0) is still alpha as of this writing, so the project owners do not provide binary downloads. Even though it's alpha, I still vastly prefer version 2.0 over 1.0 because it has fewer warts <a class="footnote-reference" href="#id7" id="id2" name="id2">[2]</a>, and its API is compatible with <a class="reference" href="http://codeplex.com/ironpython">IronPython</a>. In practice, it does seem pretty stable too.</p>
<p>I'm going to explain how I compiled and installed Python.NET 2.0 using <a class="reference" href="http://www.microsoft.com/express/vcsharp/">Visual C# 2008 Express Edition</a>, a free IDE for C#. If you don't have it installed yet, see my <a class="reference" href="http://feihonghsu.blogspot.com/2008/02/installing-visual-studio-2008-express.html">previous post</a>.</p>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">If you don't want to go through all the hassle of following the steps below, you can download the binary files I created <a class="reference" href="http://feihong.hsu.googlepages.com/PythonNET2.0.zip">here</a>.</p>
</div>
<p>Here are the steps:</p>
<ol class="arabic">
<li><p class="first">Download the <a class="reference" href="http://sourceforge.net/project/showfiles.php?group_id=162464">source files from Sourceforge</a>. You can choose either a tarball or a zip file.</p>
</li>
<li><p class="first">Extract the contents to your hard drive and open the <tt class="docutils literal"><span class="pre">pythonnet.sln</span></tt> solution file using Visual C#.</p>
</li>
<li><p class="first">Convert the solution file to the Visual C# 2008 format <a class="footnote-reference" href="#id8" id="id3" name="id3">[3]</a>.</p>
</li>
<li><p class="first">There are several projects in the solution file. The main one is called Python.Runtime. Right-click on that project and select <tt class="docutils literal"><span class="pre">Properties</span></tt>.</p>
</li>
<li><p class="first">In the <tt class="docutils literal"><span class="pre">Application</span></tt> tab, change <tt class="docutils literal"><span class="pre">Target</span> <span class="pre">Framework</span></tt> to ".NET Framework 2.0".</p>
</li>
<li><p class="first">The default is to build binaries for Python 2.5 and UCS2. If you need to change this, you need to make some additional tweaks <a class="footnote-reference" href="#id9" id="id4" name="id4">[4]</a>.</p>
</li>
<li><p class="first">From the menu, select <tt class="docutils literal"><span class="pre">Build</span> <span class="pre">-></span> <span class="pre">Configuration</span> <span class="pre">Manager</span></tt>. In the dialog that opens, change the <tt class="docutils literal"><span class="pre">Active</span> <span class="pre">solution</span> <span class="pre">configuration</span></tt> to <tt class="docutils literal"><span class="pre">Release</span></tt>. Press the <tt class="docutils literal"><span class="pre">Close</span></tt> button.</p>
</li>
<li><p class="first">From the menu, select <tt class="docutils literal"><span class="pre">Build</span> <span class="pre">-></span> <span class="pre">Build</span> <span class="pre">Solution</span></tt>.</p>
</li>
<li><p class="first">The binary files you want can be found under <tt class="docutils literal"><span class="pre">src\runtime\bin\Release</span></tt>:</p>
<blockquote>
<ul class="simple">
<li>Python.Runtime.dll</li>
<li>clr.pyd</li>
</ul>
</blockquote>
</li>
<li><p class="first">Copy the two binary files into your Python directory (e.g. <tt class="docutils literal"><span class="pre">C:\Python25</span></tt>).</p>
</li>
<li><p class="first">Test the installation by starting the shell and typing <tt class="docutils literal"><span class="pre">import</span> <span class="pre">clr</span></tt>. If there are no errors, it probably worked.</p>
</li>
</ol>
<p>If you're going to <a class="reference" href="http://us.pycon.org/2008">PyCon</a> this March and are interested in learning more about Python.NET, then come to my talk! <a class="footnote-reference" href="#id11" id="id5" name="id5">[5]</a></p>
<table class="docutils footnote" frame="void" id="id6" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1" name="id6">[1]</a></td><td>Python.NET works with <a class="reference" href="http://en.wikipedia.org/wiki/Cpython">CPython</a>, the default implementation of Python. It's not to be confused with <a class="reference" href="http://codeplex.com/ironpython">IronPython</a>, which is implemented in .NET.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="id7" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id2" name="id7">[2]</a></td><td>For example, importing <tt class="docutils literal"><span class="pre">System.Data</span></tt> is a pain if you have both .NET 1.1 and .NET 2.0 installed.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="id8" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id3" name="id8">[3]</a></td><td>Because Python.NET was originally compiled using Visual C# 2005, you will be prompted with the Visual Studio Conversion Wizard dialog. You should go ahead and convert the project.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="id9" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id4" name="id9">[4]</a></td><td>Go to the <tt class="docutils literal"><span class="pre">Properties</span> <span class="pre">-></span> <span class="pre">Build</span></tt> tab <a class="footnote-reference" href="#id9" id="id10" name="id10">[4]</a>. Change the <tt class="docutils literal"><span class="pre">Configuration</span></tt> combo box to <tt class="docutils literal"><span class="pre">Release</span></tt>. Then change the value inside the <tt class="docutils literal"><span class="pre">Conditional</span> <span class="pre">compilation</span> <span class="pre">symbols</span></tt> field. For example, <tt class="docutils literal"><span class="pre">PYTHON24,UCS4</span></tt> will build a binary for Python 2.4 with UCS4. For more details about the difference between UCS2 and UCS4, see the <tt class="docutils literal"><span class="pre">readme.html</span></tt> file inside the <tt class="docutils literal"><span class="pre">doc</span></tt> folder.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="id11" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id5" name="id11">[5]</a></td><td>According to the official <a class="reference" href="http://us.pycon.org/2008/conference/schedule/">schedule</a>, my talk will be held on Friday, March 14 at 2:45 pm.</td></tr>
</tbody>
</table>
</div>
<div class="source"><pre>.. entry_id:: tag:blogger.com,1999:blog-5424252364534723300.post-7884767366505308962
Installing Python.NET 2.0 Alpha 2 on Windows XP
===============================================
.. labels:: python, dotnet, python.net, visual studio
Python.NET_ is a project that lets you use .NET libraries from within Python [#]_. The latest version (2.0) is still alpha as of this writing, so the project owners do not provide binary downloads. Even though it's alpha, I still vastly prefer version 2.0 over 1.0 because it has fewer warts [#]_, and its API is compatible with IronPython_. In practice, it does seem pretty stable too.
.. _Python.NET: http://pythonnet.sourceforge.net
.. _IronPython: http://codeplex.com/ironpython
.. _Visual C# 2008 Express Edition: http://www.microsoft.com/express/vcsharp/
I'm going to explain how I compiled and installed Python.NET 2.0 using `Visual C# 2008 Express Edition`_, a free IDE for C#. If you don't have it installed yet, see my `previous post`_.
.. _previous post: http://feihonghsu.blogspot.com/2008/02/installing-visual-studio-2008-express.html
.. note::
If you don't want to go through all the hassle of following the steps below, you can download the binary files I created here_.
.. _here: http://feihong.hsu.googlepages.com/PythonNET2.0.zip
Here are the steps:
#. Download the `source files from Sourceforge`_. You can choose either a tarball or a zip file.
#. Extract the contents to your hard drive and open the ``pythonnet.sln`` solution file using Visual C#.
#. Convert the solution file to the Visual C# 2008 format [#]_.
#. There are several projects in the solution file. The main one is called Python.Runtime. Right-click on that project and select ``Properties``.
#. In the ``Application`` tab, change ``Target Framework`` to ".NET Framework 2.0".
#. The default is to build binaries for Python 2.5 and UCS2. If you need to change this, you need to make some additional tweaks [#]_.
#. From the menu, select ``Build -> Configuration Manager``. In the dialog that opens, change the ``Active solution configuration`` to ``Release``. Press the ``Close`` button.
#. From the menu, select ``Build -> Build Solution``.
#. The binary files you want can be found under ``src\runtime\bin\Release``:
- Python.Runtime.dll
- clr.pyd
#. Copy the two binary files into your Python directory (e.g. ``C:\Python25``).
#. Test the installation by starting the shell and typing ``import clr``. If there are no errors, it probably worked.
.. _source files from Sourceforge: http://sourceforge.net/project/showfiles.php?group_id=162464
If you're going to PyCon_ this March and are interested in learning more about Python.NET, then come to my talk! [#]_
.. _PyCon: http://us.pycon.org/2008
.. [#] Python.NET works with CPython_, the default implementation of Python. It's not to be confused with IronPython_, which is implemented in .NET.
.. [#] For example, importing ``System.Data`` is a pain if you have both .NET 1.1 and .NET 2.0 installed.
.. [#] Because Python.NET was originally compiled using Visual C# 2005, you will be prompted with the Visual Studio Conversion Wizard dialog. You should go ahead and convert the project.
.. [#] Go to the ``Properties -> Build`` tab [4]_. Change the ``Configuration`` combo box to ``Release``. Then change the value inside the ``Conditional compilation symbols`` field. For example, ``PYTHON24,UCS4`` will build a binary for Python 2.4 with UCS4. For more details about the difference between UCS2 and UCS4, see the ``readme.html`` file inside the ``doc`` folder.
.. [#] According to the official schedule_, my talk will be held on Friday, March 14 at 2:45 pm.
.. _CPython: http://en.wikipedia.org/wiki/Cpython
.. _schedule: http://us.pycon.org/2008/conference/schedule/
</pre></div>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-12567785916608688592008-02-12T08:00:00.001-06:002008-02-12T08:00:07.307-06:00Installing Visual Studio 2008 Express Edition<div class="document" id="installing-visual-studio-2008-express-edition">
<p>I recently installed <a class="reference" href="http://www.microsoft.com/express/download/default.aspx">Visual Studio 2008 Express Edition</a> on my laptop running Windows XP. In the past, I've had problems using Microsoft's Express Edition installers because of my unstable internet connection <a class="footnote-reference" href="#id3" id="id1" name="id1">[1]</a>. So this time I ignored the installers and just downloaded the All-in-One DVD ISO file <a class="footnote-reference" href="#id4" id="id2" name="id2">[2]</a>.</p>
<p>The <a class="reference" href="http://www.microsoft.com/express/download/offline.aspx">instructions</a> for installing from the ISO file aren't very good. The best and easiest way that I found to do it was to use a free tool from Microsoft called <a class="reference" href="http://blogs.techrepublic.com.com/window-on-windows/?p=42">Virtual CD-ROM Control Panel</a>. I used this tool to mount the ISO image to the <tt class="docutils literal"><span class="pre">Z:\</span></tt> drive. When I went to <tt class="docutils literal"><span class="pre">My</span> <span class="pre">Computer</span></tt> and double-clicked on <tt class="docutils literal"><span class="pre">Z:\</span></tt>, the Visual Studio installation program ran automatically. After installation was done, I went back to Virtual CD-ROM Control Panel and clicked on the <tt class="docutils literal"><span class="pre">Remove</span> <span class="pre">Drive</span></tt> button to get rid of the <tt class="docutils literal"><span class="pre">Z:\</span></tt> drive.</p>
<table class="docutils footnote" frame="void" id="id3" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1" name="id3">[1]</a></td><td>The installer is a small executable that allows you select which options you want, then automatically downloades the files you need. But if your internet connection konks out somewhere during the download process, you won't get very far, even after internet access gets restored.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="id4" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id2" name="id4">[2]</a></td><td>Scroll down all the way to the bottom of the page and you'll see a section called "Offline Install".</td></tr>
</tbody>
</table>
</div>
<div class="source"><pre>Installing Visual Studio 2008 Express Edition
=============================================
.. labels:: visual studio, install
I recently installed `Visual Studio 2008 Express Edition`_ on my laptop running Windows XP. In the past, I've had problems using Microsoft's Express Edition installers because of my unstable internet connection [#]_. So this time I ignored the installers and just downloaded the All-in-One DVD ISO file [#]_.
.. _Visual Studio 2008 Express Edition: http://www.microsoft.com/express/download/default.aspx
The instructions_ for installing from the ISO file aren't very good. The best and easiest way that I found to do it was to use a free tool from Microsoft called `Virtual CD-ROM Control Panel`_. I used this tool to mount the ISO image to the ``Z:\`` drive. When I went to ``My Computer`` and double-clicked on ``Z:\``, the Visual Studio installation program ran automatically. After installation was done, I went back to Virtual CD-ROM Control Panel and clicked on the ``Remove Drive`` button to get rid of the ``Z:\`` drive.
.. _Virtual CD-ROM Control Panel: http://blogs.techrepublic.com.com/window-on-windows/?p=42
.. _instructions: http://www.microsoft.com/express/download/offline.aspx
.. [#] The installer is a small executable that allows you select which options you want, then automatically downloades the files you need. But if your internet connection konks out somewhere during the download process, you won't get very far, even after internet access gets restored.
.. [#] Scroll down all the way to the bottom of the page and you'll see a section called "Offline Install".
</pre></div>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-2648080085765164792008-02-11T20:47:00.001-06:002008-02-11T20:47:26.667-06:00Converting from Local Time to UTC<div class="document" id="converting-from-local-time-to-utc">
<p>OK, this problem took me way, WAY too long to figure out, so I'll post it here for future reference. I was struggling with following question: How do I convert back and forth between local time and <a class="reference" href="http://en.wikipedia.org/wiki/Utc">Coordinated Universal Time</a> (UTC)?</p>
<p>The solution is actually fairly simple:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">local_to_utc</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
<span class="sd">"""Make sure that the dst flag is -1 -- this tells mktime to take daylight</span>
<span class="sd"> savings into account"""</span>
<span class="n">secs</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">mktime</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
<span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">gmtime</span><span class="p">(</span><span class="n">secs</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">utc_to_local</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
<span class="n">secs</span> <span class="o">=</span> <span class="n">calendar</span><span class="o">.</span><span class="n">timegm</span><span class="p">(</span><span class="n">t</span><span class="p">)</span>
<span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">localtime</span><span class="p">(</span><span class="n">secs</span><span class="p">)</span>
</pre></div>
<p>OK, simple enough, but I think it's kind of weird -- why the heck do I have to use a function from the <tt class="docutils literal"><span class="pre">calendar</span></tt> module to convert from UTC to local time? Why is the <tt class="docutils literal"><span class="pre">timegm</span></tt> function in <tt class="docutils literal"><span class="pre">calendar</span></tt> instead of <tt class="docutils literal"><span class="pre">time</span></tt>?</p>
<p>Even though my solution looked correct (as per my understanding from reading the Python docs), I decided I needed to do a sanity check. I compared the results of my <tt class="docutils literal"><span class="pre">local_to_utc</span></tt> function with .NET's <tt class="docutils literal"><span class="pre">DateTime.ToUniversalTime</span></tt> method. Meanwhile, I also compared my <tt class="docutils literal"><span class="pre">utc_to_local</span></tt> with .NET's <tt class="docutils literal"><span class="pre">DateTime.ToLocalTime</span></tt> method.</p>
<p>Frankly, I was surprised by the results of my first comparison:</p>
<pre class="literal-block">
Local time Python UTC .NET UTC
---------------- ---------------- ----------------
2000-03-12 02:00 2000-03-12 07:00 2000-03-12 08:00
2001-03-11 02:00 2001-03-11 07:00 2001-03-11 08:00
2002-03-10 02:00 2002-03-10 07:00 2002-03-10 08:00
2003-03-09 02:00 2003-03-09 07:00 2003-03-09 08:00
2004-03-14 02:00 2004-03-14 07:00 2004-03-14 08:00
2005-03-13 02:00 2005-03-13 07:00 2005-03-13 08:00
2006-03-12 02:00 2006-03-12 07:00 2006-03-12 08:00
2007-03-11 02:00 2007-03-11 07:00 2007-03-11 08:00
2008-03-09 02:00 2008-03-09 07:00 2008-03-09 08:00
2009-03-08 02:00 2009-03-08 07:00 2009-03-08 08:00
2010-03-14 02:00 2010-03-14 07:00 2010-03-14 08:00
</pre>
<p>The table above shows that Python and .NET disagree on a single hour in March of every year. That particular hour is always 2 AM on the start of Daylight Savings Time <a class="footnote-reference" href="#id2" id="id1" name="id1">[1]</a>.</p>
<p>I was surprised yet again when I ran the UTC to local comparison. Having already witnessed the one-day-per-year discrepancy, I figured I would see something similar in this comparison. But there were no discrepancies at all! So I won't bother showing the table.</p>
<p>When I thought about it, though, this all makes sense. That 2 AM on the start of DST is a magical date/time. From our perspective, it's 1:59 AM and then the minute hand crosses over the 12, and all of a sudden it's 3 AM. So it's like that 2 AM never existed at all. Since this date/time doesn't exist in local time, there shouldn't be a way to convert to UTC at all. Technically, the Python function should have returned <tt class="docutils literal"><span class="pre">None</span></tt>, and .NET's <tt class="docutils literal"><span class="pre">DateTime.ToUniversalTime</span></tt> method should have returned <tt class="docutils literal"><span class="pre">null</span></tt>. But instead of doing that, the designers decided to just fudge it and return a UTC value that was somewhere in the ballpark. And since it was two different designers, they chose two different values to fudge on.</p>
<p>There are no discrepancies in the conversion from UTC to local time because here, there are no values to fudge. UTC doesn't have magical date/time values. It just keeps ticking along, and never misses a beat.</p>
<p>I hope this helps other people out. I googled for this information and didn't find any results that clearly explained how to convert in both directions. As for the whole magic local time issue, I think it's not a big deal as long as you're aware of it. The designers of both libraries probably figured that most people would not bother to check if a date conversion function was returning <tt class="docutils literal"><span class="pre">None</span></tt>.</p>
<table class="docutils footnote" frame="void" id="id2" rules="none">
<colgroup><col class="label"/><col/></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#id1" name="id2">[1]</a></td><td>Daylight Savings Time is set individually by each country. Here in the US, our daylight savings period begins at 2:00 am of the second Sunday of March, and ends at 2:00 am of the first Sunday of November. The length of DST was actually <a class="reference" href="http://tf.nist.gov/general/dst.htm">changed in 2007</a> in an attempt to reduce energy consumption.</td></tr>
</tbody>
</table>
</div>
<div class="source"><pre>Converting from Local Time to UTC
=================================
.. labels:: python, utc, datetime
OK, this problem took me way, WAY too long to figure out, so I'll post it here for future reference. I was struggling with following question: How do I convert back and forth between local time and `Coordinated Universal Time`_ (UTC)?
.. _Coordinated Universal Time: http://en.wikipedia.org/wiki/Utc
The solution is actually fairly simple:
.. code:: python
def local_to_utc(t):
"""Make sure that the dst flag is -1 -- this tells mktime to take daylight
savings into account"""
secs = time.mktime(t)
return time.gmtime(secs)
def utc_to_local(t):
secs = calendar.timegm(t)
return time.localtime(secs)
OK, simple enough, but I think it's kind of weird -- why the heck do I have to use a function from the ``calendar`` module to convert from UTC to local time? Why is the ``timegm`` function in ``calendar`` instead of ``time``?
Even though my solution looked correct (as per my understanding from reading the Python docs), I decided I needed to do a sanity check. I compared the results of my ``local_to_utc`` function with .NET's ``DateTime.ToUniversalTime`` method. Meanwhile, I also compared my ``utc_to_local`` with .NET's ``DateTime.ToLocalTime`` method.
Frankly, I was surprised by the results of my first comparison::
Local time Python UTC .NET UTC
---------------- ---------------- ----------------
2000-03-12 02:00 2000-03-12 07:00 2000-03-12 08:00
2001-03-11 02:00 2001-03-11 07:00 2001-03-11 08:00
2002-03-10 02:00 2002-03-10 07:00 2002-03-10 08:00
2003-03-09 02:00 2003-03-09 07:00 2003-03-09 08:00
2004-03-14 02:00 2004-03-14 07:00 2004-03-14 08:00
2005-03-13 02:00 2005-03-13 07:00 2005-03-13 08:00
2006-03-12 02:00 2006-03-12 07:00 2006-03-12 08:00
2007-03-11 02:00 2007-03-11 07:00 2007-03-11 08:00
2008-03-09 02:00 2008-03-09 07:00 2008-03-09 08:00
2009-03-08 02:00 2009-03-08 07:00 2009-03-08 08:00
2010-03-14 02:00 2010-03-14 07:00 2010-03-14 08:00
The table above shows that Python and .NET disagree on a single hour in March of every year. That particular hour is always 2 AM on the start of Daylight Savings Time [#]_.
I was surprised yet again when I ran the UTC to local comparison. Having already witnessed the one-day-per-year discrepancy, I figured I would see something similar in this comparison. But there were no discrepancies at all! So I won't bother showing the table.
When I thought about it, though, this all makes sense. That 2 AM on the start of DST is a magical date/time. From our perspective, it's 1:59 AM and then the minute hand crosses over the 12, and all of a sudden it's 3 AM. So it's like that 2 AM never existed at all. Since this date/time doesn't exist in local time, there shouldn't be a way to convert to UTC at all. Technically, the Python function should have returned ``None``, and .NET's ``DateTime.ToUniversalTime`` method should have returned ``null``. But instead of doing that, the designers decided to just fudge it and return a UTC value that was somewhere in the ballpark. And since it was two different designers, they chose two different values to fudge on.
There are no discrepancies in the conversion from UTC to local time because here, there are no values to fudge. UTC doesn't have magical date/time values. It just keeps ticking along, and never misses a beat.
I hope this helps other people out. I googled for this information and didn't find any results that clearly explained how to convert in both directions. As for the whole magic local time issue, I think it's not a big deal as long as you're aware of it. The designers of both libraries probably figured that most people would not bother to check if a date conversion function was returning ``None``.
.. [#] Daylight Savings Time is set individually by each country. Here in the US, our daylight savings period begins at 2:00 am of the second Sunday of March, and ends at 2:00 am of the first Sunday of November. The length of DST was actually `changed in 2007`_ in an attempt to reduce energy consumption.
.. _changed in 2007: http://tf.nist.gov/general/dst.htm</pre></div>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-32333718969594274762007-10-26T07:40:00.000-05:002008-02-11T20:43:12.010-06:00Why .NET Programmers Should Care About Python<div class="document" id="why-net-programmers-should-care-about-python">
<p>OK, so you're a hotshot C# programmer (or VB, JScript, etc). Your skills are in demand, and you have a metric ton of tools at your disposal. XML, database, GUI, web, networking, threading, graphics, it's all there, and the documentation is pretty decent too, so you don't have to spend an eternity figuring out how to use it. Even more esoteric stuff isn't so hard for you. Well, maybe you have to do some extra reading but you're pretty sure you can tackle <a class="reference" href="http://en.wikipedia.org/wiki/Microsoft_XNA">game programming</a>, <a class="reference" href="http://en.wikipedia.org/wiki/Concurrency_and_Coordination_Runtime">message-passing concurrency</a>, <a class="reference" href="http://www.codeproject.com/mobilepc/StrokeViewer.asp">handwriting recognition</a>, <a class="reference" href="http://www.codeproject.com/office/modi.asp">OCR</a>, <a class="reference" href="http://en.wikipedia.org/wiki/Speech_Application_Programming_Interface">speech recognition</a>, and even <a class="reference" href="http://en.wikipedia.org/wiki/Robotics_Studio">robotics</a>. So life is good.</p>
<p>But you have this one coworker who just won't shut up about this weird little language he's always using. He says that when he programs, he doesn't use an IDE, he doesn't declare types, he doesn't use curly braces to delimit blocks of code, and he never compiles anything. &quot;WTF?&quot; you say. &quot;Who would want to use a language like that?&quot; Your coworker gets a sneaky little smile on his face as if that's just what he was waiting to hear. He pulls out a crinkly piece of paper with a list of names written on it and hands it to you. You recognize every name on that paper, and it's not because they're people you know. They're the names of companies that everyone knows.</p>
<p>Google. Microsoft. VMWare. Nokia. HP. Cisco. Sony Imageworks. Canonical. Philips. Honeywell. And the list just goes on and on and on. "What language did you say you're using?" you ask. Your coworker stands up like a bolt, throws off his sweater vest, rips off his Simpsons T-shirt in a bad imitation of Hulk Hogan, and proceeds to point triumphantly with both index fingers at a single word tattooed on his pasty, hairless chest. It says: Python. Under that there's a teeny little cartoon snake and under that some English guy with a mustache. And on his navel you see...</p>
<p>OK, enough with the story. It's getting really weird anyway. The point is, companies around the world are using Python everyday to make their products and deliver value to their customers. That means that smart people, people like you, are using Python and doing amazing things with it. And they are doing these amazing things much more efficiently than you might suspect...</p>
<p>OK, stop with the marketing talk and just show some code already. The following code is supposed to get customer information from an XML file and print the names and emails of customers who joined in 2006 or later. A snippet of that XML file might look like this:</p>
<div class="highlight"><pre><span class="nt"><customer></span>
<span class="nt"><givenName></span>Greg<span class="nt"></givenName></span>
<span class="nt"><familyName></span>Rucka<span class="nt"></familyName></span>
<span class="nt"><contact</span> <span class="na">email=</span><span class="s">"agent001@queenandcountry.com"</span>
<span class="na">phone=</span><span class="s">"986.445.1200"</span> <span class="nt">/></span>
<span class="nt"><memberSince></span>1994-01-03<span class="nt"></memberSince></span>
<span class="nt"></customer></span>
</pre></div>
<p>We want some output that looks like this:</p>
<pre class="literal-block">
Ang Lee <director@lustcaution.net>
Hayao Miyazaki <porco@ghibli.co.jp>
Joe Armstrong <joe@erlang.org>
</pre>
<p>The C# code to handle this task would look something like:</p>
<div class="highlight"><pre><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Xml.XPath</span><span class="p">;</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Task</span>
<span class="k">{</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">()</span>
<span class="k">{</span>
<span class="n">XPathDocument</span> <span class="n">xpd</span> <span class="p">=</span> <span class="k">new</span> <span class="n">XPathDocument</span><span class="p">(</span><span class="s">"customers.xml"</span><span class="p">);</span>
<span class="n">XPathNavigator</span> <span class="n">nav</span> <span class="p">=</span> <span class="n">xpd</span><span class="p">.</span><span class="n">CreateNavigator</span><span class="p">();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="n">XPathNavigator</span> <span class="n">customer</span> <span class="k">in</span> <span class="n">nav</span><span class="p">.</span><span class="n">Select</span><span class="p">(</span><span class="s">"//customer"</span><span class="p">))</span> <span class="k">{</span>
<span class="n">DateTime</span> <span class="n">memberSince</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">Parse</span><span class="p">(</span>
<span class="n">customer</span><span class="p">.</span><span class="n">SelectSingleNode</span><span class="p">(</span><span class="s">"memberSince"</span><span class="p">).</span><span class="n">Value</span><span class="p">);</span>
<span class="kt">string</span> <span class="n">givenName</span> <span class="p">=</span> <span class="n">customer</span><span class="p">.</span><span class="n">SelectSingleNode</span><span class="p">(</span><span class="s">"givenName"</span><span class="p">).</span><span class="n">Value</span><span class="p">;</span>
<span class="kt">string</span> <span class="n">familyName</span> <span class="p">=</span> <span class="n">customer</span><span class="p">.</span><span class="n">SelectSingleNode</span><span class="p">(</span><span class="s">"familyName"</span><span class="p">).</span><span class="n">Value</span><span class="p">;</span>
<span class="kt">string</span> <span class="n">email</span> <span class="p">=</span> <span class="n">customer</span><span class="p">.</span><span class="n">SelectSingleNode</span><span class="p">(</span><span class="s">"contact/@email"</span><span class="p">).</span><span class="n">Value</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">memberSince</span><span class="p">.</span><span class="n">Year</span> <span class="p">>=</span> <span class="m">2006</span><span class="p">)</span> <span class="k">{</span>
<span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">"{0} {1} <{2}>"</span><span class="p">,</span> <span class="n">givenName</span><span class="p">,</span> <span class="n">familyName</span><span class="p">,</span>
<span class="n">email</span><span class="p">);</span>
<span class="k">}</span>
<span class="k">}</span>
<span class="k">}</span>
<span class="k">}</span>
</pre></div>
<p>The equivalent Python code would be:</p>
<div class="highlight"><pre><span class="k">import</span> <span class="nn">clr</span>
<span class="k">from</span> <span class="nn">System</span> <span class="k">import</span> <span class="n">DateTime</span>
<span class="k">import</span> <span class="nn">amara</span>
<span class="n">doc</span> <span class="o">=</span> <span class="n">amara</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s">'customers.xml'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">customer</span> <span class="ow">in</span> <span class="n">doc</span><span class="o">.</span><span class="n">xml_xpath</span><span class="p">(</span><span class="s">'//customer'</span><span class="p">):</span>
<span class="k">print</span> <span class="nb">type</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
<span class="n">memberSince</span> <span class="o">=</span> <span class="n">DateTime</span><span class="o">.</span><span class="n">Parse</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">customer</span><span class="o">.</span><span class="n">memberSince</span><span class="p">))</span>
<span class="k">if</span> <span class="n">memberSince</span><span class="o">.</span><span class="n">Year</span> <span class="o">>=</span> <span class="mf">2006</span><span class="p">:</span>
<span class="k">print</span> <span class="s">"</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s"> <</span><span class="si">%s</span><span class="s">>"</span> <span class="o">%</span> <span class="p">(</span><span class="n">customer</span><span class="o">.</span><span class="n">givenName</span><span class="p">,</span> <span class="n">customer</span><span class="o">.</span><span class="n">familyName</span><span class="p">,</span>
<span class="n">customer</span><span class="o">.</span><span class="n">contact</span><span class="p">[</span><span class="s">'email'</span><span class="p">])</span>
</pre></div>
<p>Clearly, the Python code is shorter and more understandable ;-) If you don't believe me, take a look at the the two code samples side by side. We'll go over the code line by line so you understand what's going on, but first I want to mention that the Python code doesn't need to be compiled. If you are using a Python IDE (like <a class="reference" href="http://en.wikipedia.org/wiki/IDLE_%28Python%29">IDLE</a>), you can execute the script and get your result right away!</p>
<p>The first three lines import the libraries and classes that we need. You can tell that Python's <tt class="docutils literal"><span class="pre">import</span></tt> statement is roughly equivalent to .NET's <tt class="docutils literal"><span class="pre">using</span></tt> statement. Except in Python we import modules, not namespaces (the difference will be explained below).</p>
<div class="highlight"><pre><span class="k">import</span> <span class="nn">clr</span>
</pre></div>
<p>Import the clr module, which gives us access to the .NET classes.</p>
<div class="highlight"><pre><span class="k">from</span> <span class="nn">System</span> <span class="k">import</span> <span class="n">DateTime</span>
</pre></div>
<p>Import the DateTime class from the System module. This is the same .NET DateTime class you know and love.</p>
<div class="highlight"><pre><span class="k">import</span> <span class="nn">amara</span>
</pre></div>
<p>Import the amara module, which contains classes and functions for handling XML. Note that this statement does NOT import everything under the amara module, it just imports the amara module itself. Also, the amara module is not included with Python, it is actually a third party module that you can download <a class="reference" href="http://uche.ogbuji.net/tech/4suite/amara/">here</a>. Amara is similar to other DOM-based XML libraries, except much easier to use than most.</p>
<div class="highlight"><pre><span class="n">doc</span> <span class="o">=</span> <span class="n">amara</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s">'customers.xml'</span><span class="p">)</span>
</pre></div>
<p>This line creates an object named <code>doc</code> by calling the <code>parse()</code> function in the amara module. The big difference between modules in Python and namespaces in C# is that modules are objects, and can contain attributes and functions just like any other object.</p>
<div class="highlight"><pre><span class="k">for</span> <span class="n">customer</span> <span class="ow">in</span> <span class="n">doc</span><span class="o">.</span><span class="n">xml_xpath</span><span class="p">(</span><span class="s">'//customer'</span><span class="p">):</span>
</pre></div>
<p>This is a loop using the <tt class="docutils literal"><span class="pre">for</span></tt> keyword, which is similar to C#'s <tt class="docutils literal"><span class="pre">foreach</span></tt> keyword. The <tt class="docutils literal"><span class="pre">doc.xml_xpath('//customer')</span></tt> expression returns all the customer nodes inside <tt class="docutils literal"><span class="pre">doc</span></tt>. Each customer node will be bound to the variable <tt class="docutils literal"><span class="pre">customer</span></tt>.</p>
<div class="highlight"><pre><span class="n">memberSince</span> <span class="o">=</span> <span class="n">DateTime</span><span class="o">.</span><span class="n">Parse</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">customer</span><span class="o">.</span><span class="n">memberSince</span><span class="p">))</span>
</pre></div>
<p>The <tt class="docutils literal"><span class="pre">str()</span></tt> function converts any object to a string. The expression <tt class="docutils literal"><span class="pre">customer.memberSince</span></tt> refers to the <tt class="docutils literal"><span class="pre">customers/customer/memberSince</span></tt> node in the DOM. Finally, we call the <tt class="docutils literal"><span class="pre">DateTime.Parse()</span></tt> method we know and love from .NET.</p>
<div class="highlight"><pre><span class="k">if</span> <span class="n">memberSince</span><span class="o">.</span><span class="n">Year</span> <span class="o">>=</span> <span class="mf">2006</span><span class="p">:</span>
</pre></div>
<p>This is a just a simple conditional that checks if the <tt class="docutils literal"><span class="pre">Year</span></tt> property of <tt class="docutils literal"><span class="pre">memberSince</span></tt> is greater than or equal to 2006.</p>
<div class="highlight"><pre><span class="k">print</span> <span class="s">"</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s"> <</span><span class="si">%s</span><span class="s">>"</span> <span class="o">%</span> <span class="p">(</span><span class="n">customer</span><span class="o">.</span><span class="n">givenName</span><span class="p">,</span>
<span class="n">customer</span><span class="o">.</span><span class="n">familyName</span><span class="p">,</span>
<span class="n">customer</span><span class="o">.</span><span class="n">contact</span><span class="p">[</span><span class="s">'email'</span><span class="p">])</span>
</pre></div>
<p>The <tt class="docutils literal"><span class="pre">print</span></tt> statement is very similar to C's <tt class="docutils literal"><span class="pre">printf()</span></tt> function. The interpolation syntax is identical, and the usage only differs in that the values to be interpolated are listed after the <tt class="docutils literal"><span class="pre">%</span></tt> symbol. The <tt class="docutils literal"><span class="pre">customer.contact['email']</span></tt> expression refers to the <tt class="docutils literal"><span class="pre">customers/customer/contact/@email</span></tt> node in the DOM.</p>
<p>From that one example, you know almost all you possibly need to know to make effective use of amara. Python has great libraries of its own, which are worth learning because of their simplicity and flexibility. But even if you're too busy to learn them, it doesn't matter because Python allows you to leverage all of your .NET API knowledge. Here's the same example in Python, but using only .NET libraries:</p>
<div class="highlight"><pre><span class="k">import</span> <span class="nn">clr</span>
<span class="k">from</span> <span class="nn">System</span> <span class="k">import</span> <span class="n">DateTime</span>
<span class="k">from</span> <span class="nn">System.Xml.XPath</span> <span class="k">import</span> <span class="n">XPathDocument</span>
<span class="n">nav</span> <span class="o">=</span> <span class="n">XPathDocument</span><span class="p">(</span><span class="s">'customers.xml'</span><span class="p">)</span><span class="o">.</span><span class="n">CreateNavigator</span><span class="p">()</span>
<span class="k">for</span> <span class="n">customer</span> <span class="ow">in</span> <span class="n">nav</span><span class="o">.</span><span class="n">Select</span><span class="p">(</span><span class="s">'//customer'</span><span class="p">):</span>
<span class="n">memberSince</span> <span class="o">=</span> <span class="n">DateTime</span><span class="o">.</span><span class="n">Parse</span><span class="p">(</span>
<span class="n">node</span><span class="o">.</span><span class="n">SelectSingleNode</span><span class="p">(</span><span class="s">'memberSince'</span><span class="p">)</span><span class="o">.</span><span class="n">Value</span><span class="p">)</span>
<span class="k">if</span> <span class="n">memberSince</span><span class="o">.</span><span class="n">Year</span> <span class="o">>=</span> <span class="mf">2006</span><span class="p">:</span>
<span class="k">print</span> <span class="s">"</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s"> <</span><span class="si">%s</span><span class="s">>"</span> <span class="o">%</span> <span class="p">(</span>
<span class="n">customer</span><span class="o">.</span><span class="n">SelectSingleNode</span><span class="p">(</span><span class="s">'givenName'</span><span class="p">)</span><span class="o">.</span><span class="n">Value</span><span class="p">,</span>
<span class="n">customer</span><span class="o">.</span><span class="n">SelectSingleNode</span><span class="p">(</span><span class="s">'familyName'</span><span class="p">)</span><span class="o">.</span><span class="n">Value</span><span class="p">,</span>
<span class="n">customer</span><span class="o">.</span><span class="n">SelectSingleNode</span><span class="p">(</span><span class="s">'contact/@email'</span><span class="p">)</span><span class="o">.</span><span class="n">Value</span><span class="p">)</span>
</pre></div>
<p>So if you've stayed with me all the way then you might have these questions in mind:</p>
<ul class="simple">
<li>Python looks interesting, but will it really make my programming easier?</li>
<li>How do I get started learning Python syntax?</li>
<li>How do I get started learning how to use Python with .NET?</li>
</ul>
<p>All these questions will be answered in time, my friend. But this blog post has gotten rather long, and I need to go to bed.</p>
</div>
<div class="source"><pre>.. entry_id:: tag:blogger.com,1999:blog-5424252364534723300.post-3233371896959427476
Why .NET Programmers Should Care About Python
=============================================
.. labels:: python, dotnet
OK, so you're a hotshot C# programmer (or VB, JScript, etc). Your skills are in demand, and you have a metric ton of tools at your disposal. XML, database, GUI, web, networking, threading, graphics, it's all there, and the documentation is pretty decent too, so you don't have to spend an eternity figuring out how to use it. Even more esoteric stuff isn't so hard for you. Well, maybe you have to do some extra reading but you're pretty sure you can tackle `game programming`_, `message-passing concurrency`_, `handwriting recognition`_, OCR_, `speech recognition`_, and even robotics_. So life is good.
.. _game programming: http://en.wikipedia.org/wiki/Microsoft_XNA
.. _message-passing concurrency: http://en.wikipedia.org/wiki/Concurrency_and_Coordination_Runtime
.. _handwriting recognition: http://www.codeproject.com/mobilepc/StrokeViewer.asp
.. _OCR: http://www.codeproject.com/office/modi.asp
.. _speech recognition: http://en.wikipedia.org/wiki/Speech_Application_Programming_Interface
.. _robotics: http://en.wikipedia.org/wiki/Robotics_Studio
But you have this one coworker who just won't shut up about this weird little language he's always using. He says that when he programs, he doesn't use an IDE, he doesn't declare types, he doesn't use curly braces to delimit blocks of code, and he never compiles anything. &quot;WTF?&quot; you say. &quot;Who would want to use a language like that?&quot; Your coworker gets a sneaky little smile on his face as if that's just what he was waiting to hear. He pulls out a crinkly piece of paper with a list of names written on it and hands it to you. You recognize every name on that paper, and it's not because they're people you know. They're the names of companies that everyone knows.
Google. Microsoft. VMWare. Nokia. HP. Cisco. Sony Imageworks. Canonical. Philips. Honeywell. And the list just goes on and on and on. "What language did you say you're using?" you ask. Your coworker stands up like a bolt, throws off his sweater vest, rips off his Simpsons T-shirt in a bad imitation of Hulk Hogan, and proceeds to point triumphantly with both index fingers at a single word tattooed on his pasty, hairless chest. It says: Python. Under that there's a teeny little cartoon snake and under that some English guy with a mustache. And on his navel you see...
OK, enough with the story. It's getting really weird anyway. The point is, companies around the world are using Python everyday to make their products and deliver value to their customers. That means that smart people, people like you, are using Python and doing amazing things with it. And they are doing these amazing things much more efficiently than you might suspect...
OK, stop with the marketing talk and just show some code already. The following code is supposed to get customer information from an XML file and print the names and emails of customers who joined in 2006 or later. A snippet of that XML file might look like this:
.. code:: xml
<customer>
<givenName>Greg</givenName>
<familyName>Rucka</familyName>
<contact email="agent001@queenandcountry.com"
phone="986.445.1200" />
<memberSince>1994-01-03</memberSince>
</customer>
We want some output that looks like this::
Ang Lee <director@lustcaution.net>
Hayao Miyazaki <porco@ghibli.co.jp>
Joe Armstrong <joe@erlang.org>
The C# code to handle this task would look something like:
.. code:: c#
using System;
using System.Xml.XPath;
public class Task
{
public static void Main()
{
XPathDocument xpd = new XPathDocument("customers.xml");
XPathNavigator nav = xpd.CreateNavigator();
foreach (XPathNavigator customer in nav.Select("//customer")) {
DateTime memberSince = DateTime.Parse(
customer.SelectSingleNode("memberSince").Value);
string givenName = customer.SelectSingleNode("givenName").Value;
string familyName = customer.SelectSingleNode("familyName").Value;
string email = customer.SelectSingleNode("contact/@email").Value;
if (memberSince.Year >= 2006) {
Console.WriteLine("{0} {1} <{2}>", givenName, familyName,
email);
}
}
}
}
The equivalent Python code would be:
.. code:: python
import clr
from System import DateTime
import amara
doc = amara.parse('customers.xml')
for customer in doc.xml_xpath('//customer'):
print type(node)
memberSince = DateTime.Parse(str(customer.memberSince))
if memberSince.Year >= 2006:
print "%s %s <%s>" % (customer.givenName, customer.familyName,
customer.contact['email'])
Clearly, the Python code is shorter and more understandable ;-) If you don't believe me, take a look at the the two code samples side by side. We'll go over the code line by line so you understand what's going on, but first I want to mention that the Python code doesn't need to be compiled. If you are using a Python IDE (like IDLE_), you can execute the script and get your result right away!
.. _side by side: http://feihong.hsu.googlepages.com/CSharpVsPython.html
.. _IDLE: http://en.wikipedia.org/wiki/IDLE_%28Python%29
The first three lines import the libraries and classes that we need. You can tell that Python's ``import`` statement is roughly equivalent to .NET's ``using`` statement. Except in Python we import modules, not namespaces (the difference will be explained below).
.. code:: python
import clr
Import the clr module, which gives us access to the .NET classes.
.. code:: python
from System import DateTime
Import the DateTime class from the System module. This is the same .NET DateTime class you know and love.
.. code:: python
import amara
Import the amara module, which contains classes and functions for handling XML. Note that this statement does NOT import everything under the amara module, it just imports the amara module itself. Also, the amara module is not included with Python, it is actually a third party module that you can download here_. Amara is similar to other DOM-based XML libraries, except much easier to use than most.
.. _here: http://uche.ogbuji.net/tech/4suite/amara/
.. code:: python
doc = amara.parse('customers.xml')
This line creates an object named <code>doc</code> by calling the <code>parse()</code> function in the amara module. The big difference between modules in Python and namespaces in C# is that modules are objects, and can contain attributes and functions just like any other object.
.. code:: python
for customer in doc.xml_xpath('//customer'):
This is a loop using the ``for`` keyword, which is similar to C#'s ``foreach`` keyword. The ``doc.xml_xpath('//customer')`` expression returns all the customer nodes inside ``doc``. Each customer node will be bound to the variable ``customer``.
.. code:: python
memberSince = DateTime.Parse(str(customer.memberSince))
The ``str()`` function converts any object to a string. The expression ``customer.memberSince`` refers to the ``customers/customer/memberSince`` node in the DOM. Finally, we call the ``DateTime.Parse()`` method we know and love from .NET.
.. code:: python
if memberSince.Year >= 2006:
This is a just a simple conditional that checks if the ``Year`` property of ``memberSince`` is greater than or equal to 2006.
.. code:: python
print "%s %s <%s>" % (customer.givenName,
customer.familyName,
customer.contact['email'])
The ``print`` statement is very similar to C's ``printf()`` function. The interpolation syntax is identical, and the usage only differs in that the values to be interpolated are listed after the ``%`` symbol. The ``customer.contact['email']`` expression refers to the ``customers/customer/contact/@email`` node in the DOM.
From that one example, you know almost all you possibly need to know to make effective use of amara. Python has great libraries of its own, which are worth learning because of their simplicity and flexibility. But even if you're too busy to learn them, it doesn't matter because Python allows you to leverage all of your .NET API knowledge. Here's the same example in Python, but using only .NET libraries:
.. code:: python
import clr
from System import DateTime
from System.Xml.XPath import XPathDocument
nav = XPathDocument('customers.xml').CreateNavigator()
for customer in nav.Select('//customer'):
memberSince = DateTime.Parse(
node.SelectSingleNode('memberSince').Value)
if memberSince.Year >= 2006:
print "%s %s <%s>" % (
customer.SelectSingleNode('givenName').Value,
customer.SelectSingleNode('familyName').Value,
customer.SelectSingleNode('contact/@email').Value)
So if you've stayed with me all the way then you might have these questions in mind:
- Python looks interesting, but will it really make my programming easier?
- How do I get started learning Python syntax?
- How do I get started learning how to use Python with .NET?
All these questions will be answered in time, my friend. But this blog post has gotten rather long, and I need to go to bed.</pre></div>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-74626546056125471652007-03-12T14:38:00.000-05:002008-02-01T08:34:36.286-06:00Review of OpenOffice Impress<p>The first talk I ever gave at work was done in <a href="http://meyerweb.com/eric/tools/s5/">S5</a>. I like S5 quite a bit; it produces very nice HTML slides. However when showing the slides on a projector the fonts sometimes look too small and run off the edge of the screen if you try to make them bigger. When I attended PyCon earlier this year I noticed that a number of presenters had similar problems with S5. So while I still think S5 is nice, I'd like to find a better tool because I care about how the slides look on the projector.
</p>
<p>
When I decided to do a <a href="http://feihonghsu.blogspot.com/2007/03/unicode-talk.html">Unicode talk</a> at <a href="http://chipy.org/">ChiPy</a>, I went looking for alternatives. I ruled out PowerPoint pretty early on because it doesn't generate HTML slides that look good in Firefox (this may have changed in newer versions, but I refuse to upgrade just for that one feature). I also tried to use <a href="http://bruce.python-hosting.com/">Bruce</a>, but I couldn't get up and running in a short amount of time.
</p>
<p>
So I ended up going with <a href="http://en.wikipedia.org/wiki/OpenOffice.org_Impress">OpenOffice Impress</a>. Unfortunately, I came away pretty disappointed with my decision. First of all, there is a debilitating bug in Impress that disables the Text Formatting toolbar when a lot of text is entered into a text area. There are workarounds that you can use to get the Text Formatting toolbar enabled again, but it caused me to waste a lot of time.
</p>
<p>
When it came time to publish my slides on the web, I was underwhelmed by the export features:
</p>
<ul><li>Exporting to HTML causes every slide to be turned into an image, and fails to render the embedded tables (created using OpenOffice Calc).
</li><li>Exporting to PDF was mostly OK, except that if you choose the "Export notes" option you'll essentially generate two pages for each slide -- one without notes, one with notes.</li><li>The Flash (SWF) version looks fine but has no navigation buttons. Also, I don't think you can resize the text in it.
</li></ul>
<p>Although my overall experience was not good, I may use Impress again in the future. After all, the slides did look decent on the projector, and it was easy to embed Calc tables into the presentation. But if I can find something better I'll definitely be using that instead.
</p>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com0tag:blogger.com,1999:blog-5424252364534723300.post-91680876988652299652007-03-12T09:20:00.000-05:002008-02-01T08:34:55.792-06:00Unicode Talk<p>On March 8, 2007 I gave a presentation on Unicode to the <a href="http://chipy.org/">Chicago Python Users Group</a>. Unlike most talks on Unicode, mine was geared for small children.</p>
<p>Anyway, here are the downloads for the talk in various formats:</p>
<ul>
<li>
<a href="http://feihonghsu.dreamhosters.com/presentations/Unicode%20for%20Small%20Children.odp">OpenOffice Impress</a> (this is the best version to look at, if you have OpenOffice installed)
</li>
<li>
<a href="http://feihonghsu.dreamhosters.com/presentations/Unicode%20for%20Small%20Children.pdf">PDF</a> (my notes are embedded into the PDF, but you have to scroll to the end to see them)
</li>
<li>
<a href="http://feihonghsu.dreamhosters.com/presentations/unicode">HTML</a> (warning: the "horse vs unicode" and "ISO8859 vs unicode" tables don't show up)
</li>
</ul>
<p>Also, here are the <a href="http://feihonghsu.dreamhosters.com/presentations/unicode-presentation-demos.zip">demos</a> associated with the talk. I didn't have time to show any of them, but hopefully the comments inside the source files are pretty understandable.</p>Feihong Hsuhttp://www.blogger.com/profile/18242541627138425423noreply@blogger.com3