tag:blogger.com,1999:blog-86714763286615206562024-03-17T06:30:33.310-07:00Python bytesUnknownnoreply@blogger.comBlogger28125tag:blogger.com,1999:blog-8671476328661520656.post-9608504429040744102012-09-29T12:15:00.001-07:002012-09-29T16:39:38.675-07:00Python 3.3 is my Favorite Python ReleaseToday, <a href="http://python.org/download/releases/3.3.0/">Python 3.3</a> was <a href="http://mail.python.org/pipermail/python-dev/2012-September/121843.html">released</a>. During the 4.5 years I've been a CPython core developer, 6 major Python releases (2.6, 2.7, 3.0, 3.1, 3.2, and 3.3) have past by me. In this post, I will explain why 3.3 is the most exciting Python release to me. I will be cherrypicking, consult <a href="http://docs.python.org/dev/whatsnew/3.3">"What's New in Python 3.3"</a> and the <a href="http://hg.python.org/cpython/raw-file/5f854a8a0e8f/Misc/NEWS">Misc/NEWS</a> file for complete details.
<br />
<h4>
Unicode</h4>
<a href="http://www.python.org/dev/peps/pep-0393/">PEP 393</a> completely changed the internal format of Python's Unicode implementation. It does away with the concept of wide and narrow unicode builds. The encoding of a string now depends on its maximum codepoint; there are 1-byte, 2-byte, or 4-byte strings internally. This means, for example, that strings with only ASCII characters can be represented in their most compact format. Partially as a consequence, Unicode standard compilance has improved. Indexing strings always gives code points not surrogates like on < 3.3 narrow builds. <code>str.lower()</code>, <code>str.upper()</code>, and <code>str.title()</code> have been fixed to use full Unicode case-mappings instead of the simple 1-1 ones. The <code><a href="http://docs.python.org/dev/library/stdtypes#str.casefold">str.casefold</a></code> method implements the Unicode casefolding algorithm.
<br />
If the gods of PyCon talk selection smile on me, I will be giving a talk about this and the history of Unicode in Python.
<br />
<h4>
Glorious Return of the "u" Prefix</h4>
Python 3.3 allows the <code>u</code> in front of strings again. Since the <code>b</code> prefix is supported from Python 2.6, code which wants to support 2.x and 3.3 shouldn't need to use unpleasant kludges like six's <a href="http://packages.python.org/six/#binary-and-text-data"><code>u()</code> and <code>b()</code></a> functions. I don't think it would be unreasonable for libraries to only support 2.7 and 3.3+ now just to have the more natural string syntaxes.
<br />
<h4>
Many Nice Things</h4>
One of the annoyances in previous Python 3 versions was it was impossible to turn off <a href="http://www.python.org/dev/peps/pep-3134/">PEP 3134</a>'s implicit exception chaining. The <code>raise exc from None</code> syntax introduced in 3.3 prevents the <code>__context__</code> of an exception from being printed.
<br />
There were improvements in exceptions themselves. <a href="http://www.python.org/dev/peps/pep-3151/">PEP 3151</a> merged <code>IOError</code>, <code>OSError</code>, <code>WindowsError</code>, and various error types in the standard library. It also created a hierarchy of specialized exception subclasses. This means that most code dealing with IO errors won't have to dig into the <code>errno</code> module. For example, this standard pattern
<br />
<div class="highlight">
<pre><span class="k">try</span><span class="p">:</span>
<span class="n">fp</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"data"</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">OSError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">if</span> <span class="n">e</span><span class="o">.</span><span class="n">errno</span> <span class="o">!=</span> <span class="n">errno</span><span class="o">.</span><span class="n">ENOENT</span><span class="p">:</span>
<span class="k">raise</span>
<span class="c"># Create file</span>
</pre>
</div>
can become
<div class="highlight">
<pre><span class="k">try</span><span class="p">:</span>
<span class="n">fp</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">"data"</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">)</span>
<span class="k">except</span> <span class="n">FileNotFoundError</span><span class="p">:</span>
<span class="c"># Create file</span>
</pre>
</div>
. (Of course, for this sort of thing you can also use the new <code>"x"</code> mode in <code>open()</code>.)
The errors from incorrect call signatures have improved:
<br />
<div class="highlight">
<pre><span class="go">Python 3.3.0+ (3.3:7e83c8ccb1ba, Sep 29 2012, 10:34:54) </span>
<span class="go">[GCC 4.5.4] on linux</span>
<span class="go">Type "help", "copyright", "credits" or "license" for more information.</span>
<span class="gp">>>> </span><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kw1</span><span class="p">,</span> <span class="n">kw2</span><span class="p">):</span> <span class="k">pass</span>
<span class="gp">... </span>
<span class="gp">>>> </span><span class="n">f</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">kw2</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
<span class="gr">TypeError: f() missing 1 required positional argument</span>: <span class="n">'b'</span>
<span class="gp">>>> </span><span class="n">f</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">kw2</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span>
<span class="gr">TypeError: f() missing 1 required keyword-only argument</span>: <span class="n">'kw1'</span>
</pre>
</div>
In the future, I think there should be a <code>ArgumentsError</code> subclass of <code>TypeError</code> which provides programmatic access to the signature mismatch, but this is a start.
The new standard library modules, <a href="http://docs.python.org/dev/library/ipaddress">ipaddress</a>, <a href="http://docs.python.org/dev/library/lzma">lzma</a>, a dn <a href="http://docs.python.org/dev/library/unittest.mock">unittest.mock</a> are certainly worth a look.
<br />
The Windows installer has an option to set up PATH for you.
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Unknownnoreply@blogger.com12tag:blogger.com,1999:blog-8671476328661520656.post-4221549052990171522012-05-12T15:56:00.001-07:002012-05-12T15:56:48.875-07:00<a href="http://www.aosabook.org/en/index.html">The Architecture of Open Source Applications</a> volume 2 has been published. It includes <a href="http://www.aosabook.org/en/pypy.html">my chapter on PyPy</a>. You can buy the dead tree version for $35 <a href="http://www.lulu.com/shop/amy-brown-and-greg-wilson/the-architecture-of-open-source-applications-volume-ii/paperback/product-20111008.html">on Lulu</a> where all the proceeds go to Amnesty International.Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-8671476328661520656.post-6093259612865624082011-07-09T16:05:00.000-07:002011-07-10T19:26:46.523-07:00Behind the scenes of py.test's new assertion rewriting<a href="http://pytest.org">py.test</a> 2.1 was just <a href="http://codespeak.net/pipermail/py-dev/2011q3/001833.html">released</a>. py.test, which uses the Python assert statement <a href="http://pytest.org/latest/assert.html">to check test conditions</a>, has long had support for displaying intermediate values in subexpressions of a failing assert statement. This feature is called assertion introspection. Historically, py.test performed assertion introspection by <em>reinterpreting</em> failed assertions in order to glean information about subexpressions. In assertion reinterpreting, py.test actually reruns the assertion noting intermediate values during interpretation. This works pretty well but is subject to several problems, most importantly that assert statements with side-effects can produce strange results because they are evaluated twice on failure. py.test 2.1's main new feature, which I wrote (with generous sponsorship from <a href="http://merlinux.eu">Merlinux GmbH</a>), is a new assertion introspection technique called <em>assertion rewriting</em>. Assertion rewriting modifies the <a href="http://docs.python.org/dev/library/ast">AST</a> of test modules to produce subexpression information when assertions fail. This blog post will give a peek into how this is done and what the rewritten tests look like.<br /><br />py.test tries to rewrite every module that it collects as a test module. Assertion rewriting uses a <a href="http://python.org/dev/peps/pep-0302">PEP 302</a> import hook to capture test modules for rewriting. I'm happy to report doing this was easier than I expected. Most of the code in the import hook I had to write was dealing with detecting test modules rather than supporting import's extremely complicated API. Rewriting has a non-zero cost during test collection, so py.test compiles rewritten modules to bytecode and caches them in the <a href="http://www.python.org/dev/peps/pep-3147/">PEP 3147</a> PYC repository, <code>__pycache__</code>. One major thing I did have to account for was the possibility that multiple py.test processes would be writing PYC files. (This is a very real possibility when <a href="http://bitbucket.org/hpk42/pytest-xdist">the xdist plugin</a> is being used. Therefore, py.test uses only atomic operations on the rewritten PYC file. Windows, lacking atomic rename, was a pain here.<br /><br />I'm now going to demonstrate what py.test's rewriting phase does to a test module. Let's dive in with a failing test for a (broken) function that is supposed to create empty files:<br /><br /><div class="highlight"><pre><span class="pygments-kn">import</span> <span class="pygments-nn">os</span><br /><br /><span class="pygments-k">def</span> <span class="pygments-nf">make_empty_file</span><span class="pygments-p">(</span><span class="pygments-n">name</span><span class="pygments-p">):</span><br /> <span class="pygments-k">with</span> <span class="pygments-nb">open</span><span class="pygments-p">(</span><span class="pygments-n">name</span><span class="pygments-p">,</span> <span class="pygments-s">"w"</span><span class="pygments-p">)</span> <span class="pygments-k">as</span> <span class="pygments-n">fp</span><span class="pygments-p">:</span><br /> <span class="pygments-n">fp</span><span class="pygments-o">.</span><span class="pygments-n">write</span><span class="pygments-p">(</span><span class="pygments-s">"hello"</span><span class="pygments-p">)</span><br /><br /><span class="pygments-k">def</span> <span class="pygments-nf">test_make_empty_file</span><span class="pygments-p">():</span><br /> <span class="pygments-n">name</span> <span class="pygments-o">=</span> <span class="pygments-s">"/tmp/empty_test"</span><br /> <span class="pygments-n">make_empty_file</span><span class="pygments-p">(</span><span class="pygments-n">name</span><span class="pygments-p">)</span><br /> <span class="pygments-k">with</span> <span class="pygments-nb">open</span><span class="pygments-p">(</span><span class="pygments-n">name</span><span class="pygments-p">,</span> <span class="pygments-s">"r"</span><span class="pygments-p">)</span> <span class="pygments-k">as</span> <span class="pygments-n">fp</span><span class="pygments-p">:</span><br /> <span class="pygments-k">assert</span> <span class="pygments-ow">not</span> <span class="pygments-n">fp</span><span class="pygments-o">.</span><span class="pygments-n">read</span><span class="pygments-p">()</span><br /></pre></div><br /><br />This test nicely demonstrates the problem with py.test's old assertion method mentioned in the first paragraph. If we force the old assertion interpretation mode with <code>--assert=reinterp</code>, we see:<br /><br /><div style="font-family: monospace; white-space: pre-wrap"><br /> def test_make_empty_file():<br /> name = "/tmp/empty_test"<br /> make_empty_file(name)<br /> with open(name, "r") as fp:<br />> assert not fp.read()<br />E AssertionError: (assertion failed, but when it was re-run for printing intermediate values, it did not fail. Suggestions: compute assert expression before the assert or use --no-assert) <br /><br />test_empty_file.py:11: AssertionError<br /></div><br /><br />The problem is that assert statement has the side-effect of reading the file. When py.test reinterprets the assert statement, it uses the same file object, now at EOF, and <code>read()</code> returns an empty string. py.test's new rewriting mode fixes this by scanning the assert for introspection information before executing the test. Running py.test with assertion rewriting enabled gives the desired result:<br /><br /><div style="font-family: monospace; white-space: pre-wrap"><br /> def test_make_empty_file():<br /> name = "/tmp/empty_test"<br /> make_empty_file(name)<br /> with open(name, "r") as fp:<br />> assert not fp.read()<br />E assert not 'hello'<br />E + where 'hello' = <built-in method read of file object at 0xc33420>()<br />E + where <built-in method read of file object at 0xc33420> = <open file '/tmp/empty_test', mode 'r' at 0xc33420>.read<br /><br />test_empty_file.py:11: AssertionError<br /></div><br /><br />So what magic has py.test worked to display such nice debugging information? This is what Python is actually executing:<br /><br /><div class="highlight" style="white-space: pre-wrap; font-family: monospace"><span class="pygments-k">def</span> <span class="pygments-nf">test_make_empty_file</span><span class="pygments-p">():</span><br /> <span class="pygments-n">name</span> <span class="pygments-o">=</span> <span class="pygments-s">'/tmp/empty_test'</span><br /> <span class="pygments-n">make_empty_file</span><span class="pygments-p">(</span><span class="pygments-n">name</span><span class="pygments-p">)</span><br /> <span class="pygments-k">with</span> <span class="pygments-nb">open</span><span class="pygments-p">(</span><span class="pygments-n">name</span><span class="pygments-p">,</span> <span class="pygments-s">'r'</span><span class="pygments-p">)</span> <span class="pygments-k">as</span> <span class="pygments-n">fp</span><span class="pygments-p">:</span><br /> <span class="pygments-nd">@py_assert1</span> <span class="pygments-o">=</span> <span class="pygments-n">fp</span><span class="pygments-o">.</span><span class="pygments-n">read</span><br /> <span class="pygments-nd">@py_assert3</span> <span class="pygments-o">=</span> <span class="pygments-nd">@py_assert1</span><span class="pygments-p">()</span><br /> <span class="pygments-nd">@py_assert5</span> <span class="pygments-o">=</span> <span class="pygments-p">(</span><span class="pygments-ow">not</span> <span class="pygments-nd">@py_assert3</span><span class="pygments-p">)</span><br /> <span class="pygments-k">if</span> <span class="pygments-p">(</span><span class="pygments-ow">not</span> <span class="pygments-nd">@py_assert5</span><span class="pygments-p">):</span><br /> <span class="pygments-nd">@py_format6</span> <span class="pygments-o">=</span> <span class="pygments-p">(</span><span class="pygments-s">'assert not </span><span class="pygments-si">%(py4)s</span><span class="pygments-se">\n</span><span class="pygments-s">{</span><span class="pygments-si">%(py4)s</span><span class="pygments-s"> = </span><span class="pygments-si">%(py2)s</span><span class="pygments-se">\n</span><span class="pygments-s">{</span><span class="pygments-si">%(py2)s</span><span class="pygments-s"> = </span><span class="pygments-si">%(py0)s</span><span class="pygments-s">.read</span><span class="pygments-se">\n</span><span class="pygments-s">}()</span><span class="pygments-se">\n</span><span class="pygments-s">}'</span> <span class="pygments-o">%</span><br /> <span class="pygments-p">{</span><span class="pygments-s">'py0'</span><span class="pygments-p">:</span> <span class="pygments-p">(</span><span class="pygments-nd">@pytest_ar._saferepr</span><span class="pygments-p">(</span><span class="pygments-n">fp</span><span class="pygments-p">)</span> <span class="pygments-k">if</span> <span class="pygments-p">(</span><span class="pygments-s">'fp'</span> <span class="pygments-ow">in</span> <span class="pygments-nd">@py_builtins.locals</span><span class="pygments-p">()</span> <span class="pygments-ow">is</span> <span class="pygments-ow">not</span> <span class="pygments-nd">@py_builtins.globals</span><span class="pygments-p">())</span> <span class="pygments-k">else</span> <span class="pygments-s">'fp'</span><span class="pygments-p">),</span><br /> <span class="pygments-s">'py2'</span><span class="pygments-p">:</span> <span class="pygments-nd">@pytest_ar._saferepr</span><span class="pygments-p">(</span><span class="pygments-nd">@py_assert1</span><span class="pygments-p">),</span><br /> <span class="pygments-s">'py4'</span><span class="pygments-p">:</span> <span class="pygments-nd">@pytest_ar._saferepr</span><span class="pygments-p">(</span><span class="pygments-nd">@py_assert3</span><span class="pygments-p">)})</span><br /> <span class="pygments-k">raise</span> <span class="pygments-ne">AssertionError</span><span class="pygments-p">(</span><span class="pygments-nd">@pytest_ar._format_explanation</span><span class="pygments-p">(</span><span class="pygments-nd">@py_format6</span><span class="pygments-p">))</span><br /> <span class="pygments-k">del</span> <span class="pygments-nd">@py_assert5</span><span class="pygments-p">,</span> <span class="pygments-nd">@py_assert1</span><span class="pygments-p">,</span> <span class="pygments-nd">@py_assert3</span><br /></div><br /><br />As you can see, it's not going to be winning any awards for beautiful Python! (Ideally, though, you'll never have to see or think about it.) Examining the rewritten code, we see a lot of internal variables starting with "@" have been created. The "@", invalid in Python identifiers, is to make sure internal names don't conflict with any user-defined names which might be in the scope. In the first four written lines under the with statement, the test of the assert statement has been expanded into its component subexpressions. This allows py.test to display the values of subexpressions should the assertion fail. If the assertion fails, the if statement in the fifth line of rewriting evaluates to <code>True</code> and a <code>AssertionError</code> will be raised. Under the if statement is the real mess. This is where the helpful error message is generated. The line starting with <code>@py_format6</code> is simply does string formatting (with <code>%</code>) on a template generated from the structure of the assert statement. This template is filled in with the intermediate values of the expressions collected above. <code>@py_builtins</code> is the builtins module, used in case the test is shadowing builtins the rewriting code uses. The <code>@pytest_ar</code> variable is a special module of assertion formatting helpers. For example, <code>@pytest_ar._saferepr</code> is like builtin <code>repr</code> but gracefully handles long reprs and <code>__repr__</code> methods that raise exceptions. A non-obvious trick in the format dict is the expression <code>@pytest_ar._saferepr(fp) if ('fp' in @py_builtins.locals() is not @py_builtins.globals()) else 'fp'</code>. This checks whether <code>fp</code> is a local variable or not and customizes the display accordingly. After the initial formatting, the helper function <code>_format_explanation</code> is called. This function produces the indentation and "+" you see in the error message. Finally, we note that if the assertion doesn't fail, py.test cleans up after itself by deleting temporary variables.<br /><br />The example above is a fairly tame (and luckily also typical) assertion. Rewriting gets more "exciting" when boolean operations and comparisons enter because they require short circuit evaluation, which complicates both the expansion of expressions and formatting (think lots of nested ifs).<br /><br />In conclusion, py.test's new assertion rewriting fixes some long standing issues with assertion introspection and continues py.test's long tradition of excellent debugging support. (There are now <strong>three(!)</strong> assertion introspection methods in py.test: two reinterpretation implementations as well as rewriting) I just hope I haven't scared you completely off py.test! :)Unknownnoreply@blogger.com162tag:blogger.com,1999:blog-8671476328661520656.post-86213846368951257642011-03-15T08:54:00.000-07:002011-03-15T09:07:47.329-07:00six 1.0.0 final finally releasedI finally found time to release <a href="http://pypi.python.org/pypi/six">six</a> 1.0.0. six is a Python 2 and 3 compatibility library. You can find the <a href="http://packages.python.org/six/">documentation</a> and <a href="http://pypi.python.org/pypi/six">download it</a> on PyPI.<br /><br />There haven't been many changes since the beta: one bugfix and one new advanced feature. The <a href="https://bitbucket.org/gutworth/six/issue/2/">bugfix</a> is that unicode escapes are now properly decoded with the u() fake literal in both Python 2 and 3. The feature is that there is now <a href="http://packages.python.org/six/#advanced-customizing-renames">an api</a> for adding items to the "six.moves" interface. This was requested by <a href="http://activestate.com">ActiveState</a>, which uses six in the ActivePython package manager.<br /><br />Enjoy!Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-8671476328661520656.post-4660400655327005112010-11-20T13:45:00.000-08:002010-11-20T14:08:31.239-08:00New version of six, lean and meanI just released a <a href="http://pypi.python.org/pypi/six">new version a of six</a>, my Python 2/3 compatibility library. The main feature in this release has that six has been flattened into one source file on the philosophy of "flat is better than nested" and for ease of distributing in projects. I've also switched from Bazaar to Mercurial, since the latter seems more popular and it's all the same to me. The issue tracker and source code is no <a href="http://bitbucket.org/gutworth/six">on BitBucket</a>.<br /><br />I'm calling this version, 1.0.0 beta 1. Assuming no one complains, I think I'd like to release a final version in the next month or so.<br /><br />Your feedback is appreciated.Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-8671476328661520656.post-62197937436227644052010-06-29T11:02:00.000-07:002010-06-29T13:42:52.630-07:00Six: Python 2/3 compatibility helpersIncreasingly, I've seen a movement towards supporting Python 2 and Python 3 in the same code base. Having ported a <a href="http://pytest.org">few</a> <a href="https://launchpad.net/testtools">projects</a> myself, I decided to collect the code I've duplicated between them into a library. The result is <a href="http://pypi.python.org/pypi/six">six</a>. It includes fake byte and unicode literals, <code>b()</code> and <code>u()</code> and has wrappers for syntax changes such as <code>print</code> and <code>exec</code>. You can check out the documentation on <a href="http://packages.python.org/six/">PyPi</a>.The license is MIT, so I hope it can see wide use in projects planning to support Python 2 and 3 simultaneously.Unknownnoreply@blogger.com8tag:blogger.com,1999:blog-8671476328661520656.post-61191370764869153262010-03-26T09:27:00.000-07:002010-03-26T10:17:17.967-07:00On commit messagesI would like to address the issue of commit messages. Good commit messages can make finding bugs and understanding the timeline of a project easy, and bad ones can result in an infuriating waste of time reading diffs and trying to locate information.<br /><br />First of all, all commits should be atomic, that is they shouldn't include unrelated changes. Fixing a typo or spacing while fixing bug in related code is acceptable, but fixing 6 bugs and adding 2 features in the same commit makes it hard for people to parse out what change was for in the future. A good rule of thumb is that if a summary of your changes can't fit in one line, it's probably too big.<br /><br />The first line of the commit message is most important part. This is especially true today, where many DVCSes only show the first line of the commit by default in their log command. The summary line should succinctly summarize what your change is and what it accomplishes. It need not be a full sentence, but just a bug number or general statement ("fix this") is not appropriate. The best summary lines quickly inform any log browser of the purpose and changes in the commit. Summary lines should also never be wrapped. Nothing is more annoying than reading a summary line which is cut off in the middle by a line break. Simple typo fixes do not require complicated messages. Good examples:<br /><pre>fix #2345 by preventing add() from accepting strings<br /><br />fix a segfault in foo_my_bars() #4563<br /><br />fix spelling<br /><br />add a Python interface to the tokenizer #3222</pre><br />and bad ones:<br /><pre>test and a fix<br /><br />ugg<br /><br />bah<br /><br />a huge change to Foo class<br /><br />why does this not work?<br /><br />bug #4543</pre><br /><br />After the summary line can optionally come a body. A blank line should always separate the commit message from the body and different sections of the body from another. Bodies should also always be line wrapped. The body can include any of the following:<br /><ul><br /><li>Bullet points describing various aspect of the change in more detail.</li><br /><li>A paragraph description explaining why how something was implemented or why it's written a certain way.</li><br /><li>A reference to mailing list discussions or decisions that lead to the commit.</li><br /><li>Authors and attributions.</li><br /><li>Any other significant information about the commit. For example, explain how it affects external components or might result in unexpected behavior.</li><br /></ul><br />Some projects follow the convention of listing affected files in bullet points and describing the individual changes to each. I personally find a prose summary of the changes in the body along with a diff or the verbose version of the log which shows changed files more helpful than this technique.<br />Good examples of complete commit messages:<br /><pre><br />"""<br />normalize encoding before opening file #3242<br /><br />This change requires that tokenizer.c be linked with the Unicode<br />library.<br />"""<br /><br />"""<br />silence foo warnings by default<br /><br />Approved by BDFL in<br />http://mail.python.org/pipermail/mailinglist/bladh.html<br />"""<br /><br />"""<br />support unicode in shlex module #4523<br /><br />This is implemented by providing a separate class for Unicode and<br />requiring a locale to be set before parsing commences.<br /><br />Patch by J. Hacker and J. Programmer<br />"""<br /><br />"""<br />boost the speed of keyword argument comparisons<br /><br />This improves some function calls by over 30% by comparing for<br />identity before falling back to the regular comparison. stringobject.c<br />was modified to provide faster access to a string's value.<br />"""<br /></pre>Unknownnoreply@blogger.com19tag:blogger.com,1999:blog-8671476328661520656.post-63826944434495983082009-10-03T14:46:00.000-07:002009-10-03T14:53:46.069-07:00% formatting to str.format converterRecent discussions on Python-dev have revolved around transitioning the standard library to the new str.format method. One suggestion was to write a automatic converter for old format strings to new ones. I've taken on the task and written mod2format at <a href="https://code.launchpad.net/~gutworth/+junk/mod2format">https://code.launchpad.net/~gutworth/+junk/mod2format</a>. You can try it out by running "python3 -m mod2format [your format strings here]".Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-8671476328661520656.post-20363711452245017292009-09-04T20:28:00.000-07:002009-09-09T13:25:46.889-07:00Reivew: IronPython in action<i>Disclaimer: Manning Press and Michael Ford very generously sent me a free copy of the book.</i><br /><br />One thing that always slightly annoys me when I'm reading a book about Python programming is having the first few chapters devoted to introducing the Python language. However, I'm sure experienced .NET people felt the same while scanning through the introduction chapters to .NET, which was totally new to me. (I'm also glad there was an appendix about C# syntax; I learned that C# seems to have invented a new syntax or keyword for every possible programming paradigm.) <a href="http://ironpythoninaction.com">IronPython in Action</a> seems to do a very job, overall, of catering both Python programmers tiptoeing into IronPython and .NET and C# developers finding the light of dynamic programming.<br /><br />I found the web programming part of the book, especially the part on Silverlight, most interesting, since embedding Python in the browser seems like a lot more fun than writing cross-browser JavaScript. Michael Foord's <a href="http://trypython.org">Try Python</a> (<a href="http://code.google.com/p/trypython/">source</a>) is a good demonstration of what can be accomplished. (Though, I wonder if PyPy's sandboxing could someday be used in the browser to do the same thing.)<br /><br />I would have appreciated a chapter or section on parallel processing, since IronPython offers much better threading and concurrency primitives than CPython. Perhaps an example where IronPython can perform a task that would be impossible on other implementations of Python is in order. I want to see how .NET can make concurrency easy and pythonic.<br /><br />Before reading this book, I had dismissed .NET as a non-cross-platform hunk of Javaish APIs. I see now, though, that IronPython is able to combine the beauty of Python with some of .NET's better APIs (I would still rather use PyQt for GUI programming. Windows Forms has not improved.) to make a powerful development platform.Unknownnoreply@blogger.com79tag:blogger.com,1999:blog-8671476328661520656.post-85242492748444958822009-08-25T10:17:00.000-07:002009-08-25T10:20:31.607-07:00parser-compiler branch mergedThe PyPy project I have been working on over the summer, rewriting the parser and compiler, has finally been merged back to trunk (during the now-ending <a href="http://morepypy.blogspot.com/2009/08/gothenburg-jit-sprint-report.html">JIT sprint</a> in Gothenburg, Sweden). I wrote a <a href="http://morepypy.blogspot.com/2009/08/pypy-gets-new-compiler_25.html">little summary</a> up about it on the <a href="http://morepypy.blogspot.com">PyPy blog</a>.Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-8671476328661520656.post-27080784167044969462009-06-27T14:14:00.000-07:002009-06-27T18:43:23.803-07:00Python 3.1 released!I'm happy <a href="http://mail.python.org/pipermail/python-dev/2009-June/090224.html"> to announce</a> that today Python 3.1 was released. I won't dwell the new features, since those are more completely listed <a href="http://doc.python.org/3.1/whatsnew/3.1.html">elsewhere</a>. I'm quite happy with this release. A lot of work has been put into 3.x as stable as its older 2.x siblings. I would like to see a lot of libraries and applications start serious looking at the port to 3.x now. As always there's a bunch of core developers waiting to help on the <a href="http://mail.python.org/listinfo/python-porting">python-porting mailing list</a>.<br /><br />Anyway, 3.1 is available for download in source and several binary formats on <a href="http://python.org/download/releases/3.1">python.org</a>.Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-8671476328661520656.post-64217145663011922942009-05-06T16:49:00.000-07:002009-05-06T17:08:03.744-07:00Python 3.1 beta 1 releasedI'm pleased to announce that the first beta of Python 3.1 has been released. In addition to the features found in the previous alphas, the beta has several more improvements. Most importantly, I think, is <a href="http://python.org/dev/peps/pep-0383/">PEP 383</a>. It defines a way for undecodable paths in file systems to be safely round tripped from Unicode strings. The repr of floats also now uses a <a href="http://bugs.python.org/1580">new algorithm</a> which determines the shortest possible value.<br /><br />It <a href="http://python.org/dev/peps/pep-0375">is planned</a> that this will be the only beta in order for 3.1 to make a final in late June. Please <a href="http://python.org/download/releases/3.1">download it and try it out</a>. This is 3.x's future, and in my opinion, much of an improvement. As always, you can submit any problems you see to <a href="http://bugs.python.org">bugs.python.org</a>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-8671476328661520656.post-68037189083560263642009-03-24T15:34:00.000-07:002009-03-24T16:03:03.975-07:00unittest - now with test skipping (finally)Yesterday, I was happy to <a href="http://svn.python.org/view?view=rev&revision=70555">commit</a> a patch which added <a href="http://docs.python.org/dev/library/unittest.html#unittest-skipping">test skipping and expected failure support</a> to the venerable <a href="http://doc.python.org/library/unittest.html">unittest module</a>. It adds a skip() method to TestCase, which marks the current test being run as skipped, as well as a set of useful decorators. Here's a short example:<br /><br /><div class="highlight"><pre><span style="color: #AA22FF; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">sys</span><br /><span style="color: #AA22FF; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">unittest</span><br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">SkippingExample</span>(unittest<span style="color: #666666">.</span>TestCase):<br /><br /> <span style="color: #AA22FF">@unittest.skip</span>(<span style="color: #BB4444">"testing skipping"</span>)<br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">test_skip_me</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>fail(<span style="color: #BB4444">"shouldn't happen"</span>)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">test_normal</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>assertEqual(<span style="color: #666666">1</span>, <span style="color: #666666">1</span>)<br /><br /> <span style="color: #AA22FF">@unittest.skipIf</span>(sys<span style="color: #666666">.</span>version_info <span style="color: #666666"><</span> (<span style="color: #666666">2</span>, <span style="color: #666666">6</span>),<br /> <span style="color: #BB4444">"not supported in this veresion"</span>)<br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">test_show_skip_if</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #008800; font-style: italic"># testing some things here</span><br /> <span style="color: #AA22FF; font-weight: bold">pass</span><br /><br /> <span style="color: #AA22FF">@unittest.expectedFailure</span><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">test_expected_failure</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>fail(<span style="color: #BB4444">"this should happen unfortunately"</span>)<br /><br /><br /><span style="color: #008800; font-style: italic"># Yes, you can skip whole classes, too!</span><br /><span style="color: #AA22FF">@unittest.skip</span>(<span style="color: #BB4444">"classing skipping"</span>)<br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">CompletelySkippedTest</span>(unittest<span style="color: #666666">.</span>TestCase):<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">test_not_run_at_all</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>fail(<span style="color: #BB4444">"shouldn't happen"</span>)<br /><br /><br /><span style="color: #AA22FF; font-weight: bold">if</span> __name__ <span style="color: #666666">==</span> <span style="color: #BB4444">"__main__"</span>:<br /> unittest<span style="color: #666666">.</span>main()<br /></pre></div><br /><br />Running it in verbose mode gives:<br /><br /><pre><br />__main__.CompletelySkippedTest ... skipped 'classing skipping'<br />test_expected_failure (__main__.SkippingExample) ... expected failure<br />test_normal (__main__.SkippingExample) ... ok<br />test_show_skip_if (__main__.SkippingExample) ... ok<br />test_skip_me (__main__.SkippingExample) ... skipped 'testing skipping'<br /><br />----------------------------------------------------------------------<br />Ran 5 tests in 0.010s<br /><br />OK (skipped=2, expected failures=1)<br /></pre><br /><br />I have high hopes for this and Python's regression tests. Hopefully it will simplify the ugly system of test skipping we have now. It should also help us pacify other implementations who want CPython implementation detail tests skipped.Unknownnoreply@blogger.com11tag:blogger.com,1999:blog-8671476328661520656.post-8919523227232242132009-02-14T08:12:00.000-08:002009-02-14T08:33:32.696-08:00Python 3.0.1 releasedThe first bugfix release, 3.0.1, of the new Python 3.x series has <a href="http://mail.python.org/pipermail/python-dev/2009-February/086086.html">been released</a>! Many embarrassing bugs have been fixed. Among other things:<br /><br /><ul><br /><li>The <a href="http://doc.python.org/library/wsgiref.html">wsgiref</a> package has been fixed for 3.x.</li><br /><li>A few hideous bugs in the new IO implementation have been squashed. In addition, a few cases have been optimized. (Note that IO in 3.x is still quite a bit slower than 2.x; more on that later.)</li><br /><li>Unbuffered standard streams (the "-u" flag) have been restored.</li><br /></ul><br /><br />This is actually a bit more than an average point release. Somehow, the builtin cmp() and __cmp__ slipped into the final release and has been removed in 3.0.1.<br /><br />Our next goal is 3.1. We plan to compress our rather huge release cycle to make 3.1 between 1/2 and 1 year after 3.0. The focus of 3.1 will be stabilizing the feature set and change in 3.x. This is includes the rewrite of IO in C for speed and Brett's <a href="http://doc.python.org/dev/3.0/library/importlib.html">rewrite of import in Python</a>.Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-8671476328661520656.post-53947207882319630472009-01-01T07:32:00.000-08:002009-01-01T08:07:00.170-08:00MRO magicHere's some more less publicized evil you can accomplish with metaclasses. Here's a simple example file: (Note that although I'm using Python 3.0, this works with all new-style class supporting versions.)<br /><br /><div class="highlight"><pre><span style="color: #008800; font-style: italic"># mromagic.py</span><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">A</span>(<span style="color: #AA22FF">object</span>):<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">a_method</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF">print</span>(<span style="color: #BB4444">"A"</span>)<br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">B</span>(<span style="color: #AA22FF">object</span>):<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">b_method</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF">print</span>(<span style="color: #BB4444">"B"</span>)<br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">MROMagicMeta</span>(<span style="color: #AA22FF">type</span>):<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">mro</span>(cls):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> (cls, B, <span style="color: #AA22FF">object</span>)<br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">C</span>(A, metaclass<span style="color: #666666">=</span>MROMagicMeta):<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">c_method</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF">print</span>(<span style="color: #BB4444">"C"</span>)<br /></pre></div><br /><br />Now let's play with this a little:<br /><br /><div class="highlight"><pre><span style="color: #000080; font-weight: bold">>>> </span><span style="color: #AA22FF; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">mromagic</span><br /><span style="color: #000080; font-weight: bold">>>> </span>mycls <span style="color: #666666">=</span> mromagic<span style="color: #666666">.</span>C()<br /><span style="color: #000080; font-weight: bold">>>> </span>mycls<br /><span style="color: #808080"><mromagic.C object at 0x622890></span><br /><span style="color: #000080; font-weight: bold">>>> </span>mycls<span style="color: #666666">.</span>c_method()<br /><span style="color: #808080">C</span><br /><span style="color: #000080; font-weight: bold">>>> </span>mycls<span style="color: #666666">.</span>a_method()<br /><span style="color: #0040D0">Traceback (most recent call last):</span><br /> File <span style="color: #AA22FF">"<stdin>"</span>, line <span style="color: #666666">1</span>, in <module><br /><span style="color: #0000FF">AttributeError</span>: 'C' object has no attribute 'a_method'<br /><span style="color: #000080; font-weight: bold">>>> </span>mycls<span style="color: #666666">.</span>b_method()<br /><span style="color: #808080">B</span><br /><span style="color: #000080; font-weight: bold">>>> </span><span style="color: #AA22FF">type</span>(mycls)<span style="color: #666666">.</span><span style="border: 1px solid #FF0000">__</span>mro__<br /><span style="color: #808080">(<class 'mromagic.C'>, <class 'mromagic.B'>, <class 'object'>)</span><br /><span style="color: #000080; font-weight: bold">>>> </span><span style="color: #AA22FF">type</span>(mycls)<span style="color: #666666">.</span><span style="border: 1px solid #FF0000">__</span>bases__<br /><span style="color: #808080">(<class 'mromagic.A'>,)</span><br /></pre></div><br /><br />How does this work? By overriding mro() on the a metaclass we can define a custom __mro__ for our class. Python will then traverse it instead of the default implementation, which is provided by type.mro().Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-8671476328661520656.post-52107004524072202762008-12-11T08:41:00.000-08:002008-12-11T08:49:31.953-08:00Get help porting your package!To help the community with porting their packages to Python 3, we have <a href="http://mail.python.org/pipermail/python-dev/2008-December/083951.html">created</a> the <a href="http://mail.python.org/mailman/listinfo/python-porting">python-porting mailing list</a>. Many core developers are subscribed to the list, so you should be able to get excellent advice on 2to3, the bytes/unicode split, C-API, or other incompatibilities.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8671476328661520656.post-78790610488956185372008-12-03T10:40:00.000-08:002008-12-03T19:03:44.570-08:00Is it all futile?Today, the much anticipated <a href="http://www.python.org/download/releases/3.0/">Python 3.0 final</a> <a href="http://mail.python.org/pipermail/python-dev/2008-December/083824.html">was released</a>. Truly, this is a historic release for the Python community, the first intentional incompatible Python release. It's been a long time in the making, and I applaud everybody who is responsible for proving Py3k is not vaporware. Guido and the other decision makers on Python-dev also deserve credit for not making py3k changes too gratuitous; <a href="http://www.python.org/dev/peps/pep-3099/">many revolutionary ideas and features</a> were proposed and rejected. I have every confidence that every incompatibility was well thought out. Much thought has also been given to making the transition as easy as possible for the community. The suggested migration path, fixing Py3k warnings in 2.6 and then applying 2to3, <a href="http://wiki.python.org/moin/Early2to3Migrations">has been used</a> with a fair amount of success on several projects. We've even had several Py3k <a href="http://mail.python.org/pipermail/python-list/2008-November/516224.html">love letters</a>!<br /><br />Still, I can't help being a little worried. I think the bytes and str divide will be difficult for people especially with IO where everything has to be dealt with in bytes. We may see many "x.encode('ascii')" lines popping up all over codebases. Userland libraries will need to maintain compatibility with 2.4 and 2.5 for a while; that significantly complicates the dream of maintaining just one branch for 2.x and py3k. 2to3 is not even close to perfect and will only correct the surface incompatibilities of syntax between the versions. I'm also concerned about burn out. The excitement of a new major version will certainly spur an interest in porting for a few months, but I suspect it won't be so fun after the aura wears off a bit. I hope common base libraries (PIL, Twisted, lxml, etc...) are ported soon. It will build the bridge for everything else to cross over too.<br /><br />Of course, what I'm forgetting is the amazing Python community. Whatever the results, a new era has certainly begun. We just need time.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-8671476328661520656.post-85774643405631926552008-10-19T09:44:00.001-07:002008-10-19T09:59:16.856-07:00Pure Python Dictionary ImplementationFor those curious about how CPython's dict implementation works, I've written a Python implementation using the same algorithms. Aside from the education value, it's pretty useless because it doesn't support None as a value and is extremely slow. You can get the source in a Bazaar repo: http://code.python.org/python/users/benjamin.peterson/pydict/<br /><br /><div class="highlight"><pre><span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic">A Python dict implementation.</span><br /><span style="color: #BB4444; font-style: italic">"""</span><br /><br /><span style="color: #AA22FF; font-weight: bold">import</span> <span style="color: #0000FF; font-weight: bold">collections</span><br /><br />MINSIZE <span style="color: #666666">=</span> <span style="color: #666666">8</span><br />PERTURB_SHIFT <span style="color: #666666">=</span> <span style="color: #666666">5</span><br />dummy <span style="color: #666666">=</span> <span style="color: #BB4444">"<dummy key>"</span><br /><br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">Entry</span>(<span style="color: #AA22FF">object</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> A hash table entry.</span><br /><br /><span style="color: #BB4444; font-style: italic"> Attributes:</span><br /><span style="color: #BB4444; font-style: italic"> * key - The key for this entry.</span><br /><span style="color: #BB4444; font-style: italic"> * hash - The has of the key.</span><br /><span style="color: #BB4444; font-style: italic"> * value - The value associated with the key.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /><br /> __slots__ <span style="color: #666666">=</span> (<span style="color: #BB4444">"key"</span>, <span style="color: #BB4444">"value"</span>, <span style="color: #BB4444">"hash"</span>)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__init__</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>key <span style="color: #666666">=</span> <span style="color: #AA22FF">None</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>value <span style="color: #666666">=</span> <span style="color: #AA22FF">None</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>hash <span style="color: #666666">=</span> <span style="color: #666666">0</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__repr__</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #BB4444">"<Entry: key={0} value={1}>"</span><span style="color: #666666">.</span>format(<span style="color: #AA22FF">self</span><span style="color: #666666">.</span>key, <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>value)<br /><br /><br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">Dict</span>(<span style="color: #AA22FF">object</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> A mapping interface implemented as a hash table.</span><br /><br /><span style="color: #BB4444; font-style: italic"> Attributes:</span><br /><span style="color: #BB4444; font-style: italic"> * used - The number of entires used in the table.</span><br /><span style="color: #BB4444; font-style: italic"> * filled - used + number of entries with a dummy key.</span><br /><span style="color: #BB4444; font-style: italic"> * table - List of entries; contains the actual dict data.</span><br /><span style="color: #BB4444; font-style: italic"> * mask - Length of table - 1. Used to fetch values.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /><br /> __slots__ <span style="color: #666666">=</span> (<span style="color: #BB4444">"filled"</span>, <span style="color: #BB4444">"used"</span>, <span style="color: #BB4444">"mask"</span>, <span style="color: #BB4444">"table"</span>)<br /><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__init__</span>(<span style="color: #AA22FF">self</span>, arg<span style="color: #666666">=</span><span style="color: #AA22FF">None</span>, <span style="color: #666666">**</span>kwargs):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>clear()<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_update(arg, kwargs)<br /><br /> <span style="color: #AA22FF">@classmethod</span><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">fromkeys</span>(cls, keys, value<span style="color: #666666">=0</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Return a new dictionary from a sequence of keys.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> d <span style="color: #666666">=</span> cls()<br /> <span style="color: #AA22FF; font-weight: bold">for</span> key <span style="color: #AA22FF; font-weight: bold">in</span> keys:<br /> d[key] <span style="color: #666666">=</span> value<br /> <span style="color: #AA22FF; font-weight: bold">return</span> d<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">clear</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Clear the dictionary of all data.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>filled <span style="color: #666666">=</span> <span style="color: #666666">0</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">=</span> <span style="color: #666666">0</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask <span style="color: #666666">=</span> MINSIZE <span style="color: #666666">-</span> <span style="color: #666666">1</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table <span style="color: #666666">=</span> []<br /> <span style="color: #008800; font-style: italic"># Initialize the table to a clean slate of entries.</span><br /> <span style="color: #AA22FF; font-weight: bold">for</span> i <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #AA22FF">range</span>(MINSIZE):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table<span style="color: #666666">.</span>append(Entry())<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">pop</span>(<span style="color: #AA22FF">self</span>, <span style="color: #666666">*</span>args):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Remove and return the value for a key.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> have_default <span style="color: #666666">=</span> <span style="color: #AA22FF">len</span>(args) <span style="color: #666666">==</span> <span style="color: #666666">2</span><br /> <span style="color: #AA22FF; font-weight: bold">try</span>:<br /> v <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span>[args[<span style="color: #666666">0</span>]]<br /> <span style="color: #AA22FF; font-weight: bold">except</span> <span style="color: #D2413A; font-weight: bold">KeyError</span>:<br /> <span style="color: #AA22FF; font-weight: bold">if</span> have_default:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> args[<span style="color: #666666">1</span>]<br /> <span style="color: #AA22FF; font-weight: bold">raise</span><br /> <span style="color: #AA22FF; font-weight: bold">else</span>:<br /> <span style="color: #AA22FF; font-weight: bold">del</span> <span style="color: #AA22FF">self</span>[args[<span style="color: #666666">0</span>]]<br /> <span style="color: #AA22FF; font-weight: bold">return</span> v<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">popitem</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Remove and return any key-value pair from the dictionary.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">==</span> <span style="color: #666666">0</span>:<br /> <span style="color: #AA22FF; font-weight: bold">raise</span> <span style="color: #D2413A; font-weight: bold">KeyError</span>(<span style="color: #BB4444">"empty dictionary"</span>)<br /> entry0 <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table[<span style="color: #666666">0</span>]<br /> entry <span style="color: #666666">=</span> entry0<br /> i <span style="color: #666666">=</span> <span style="color: #666666">0</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry0<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #008800; font-style: italic"># The first entry in the table's hash is abused to hold the index to</span><br /> <span style="color: #008800; font-style: italic"># the next place to look for a value to pop.</span><br /> i <span style="color: #666666">=</span> entry0<span style="color: #666666">.</span>hash<br /> <span style="color: #AA22FF; font-weight: bold">if</span> i <span style="color: #666666">></span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask <span style="color: #AA22FF; font-weight: bold">or</span> i <span style="color: #666666"><</span> i:<br /> i <span style="color: #666666">=</span> <span style="color: #666666">1</span><br /> entry <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table[i]<br /> <span style="color: #AA22FF; font-weight: bold">while</span> entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> i <span style="color: #666666">+=</span> <span style="color: #666666">1</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> i <span style="color: #666666">></span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask:<br /> i <span style="color: #666666">=</span> <span style="color: #666666">1</span><br /> entry <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table[i]<br /> res <span style="color: #666666">=</span> entry<span style="color: #666666">.</span>key, entry<span style="color: #666666">.</span>value<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_del(entry)<br /> <span style="color: #008800; font-style: italic"># Set the next place to start.</span><br /> entry0<span style="color: #666666">.</span>hash <span style="color: #666666">=</span> i <span style="color: #666666">+</span> <span style="color: #666666">1</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> res<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">setdefault</span>(<span style="color: #AA22FF">self</span>, key, default<span style="color: #666666">=0</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> If key is in the dictionary, return it. Otherwise, set it to the default</span><br /><span style="color: #BB4444; font-style: italic"> value.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> val <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_lookup(key)<span style="color: #666666">.</span>value<br /> <span style="color: #AA22FF; font-weight: bold">if</span> val <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #AA22FF">self</span>[key] <span style="color: #666666">=</span> default<br /> <span style="color: #AA22FF; font-weight: bold">return</span> default<br /> <span style="color: #AA22FF; font-weight: bold">return</span> val<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_lookup</span>(<span style="color: #AA22FF">self</span>, key):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Find the entry for a key.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> key_hash <span style="color: #666666">=</span> <span style="color: #AA22FF">hash</span>(key)<br /> i <span style="color: #666666">=</span> key_hash <span style="color: #666666">&</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask<br /> entry <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table[i]<br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span> <span style="color: #AA22FF; font-weight: bold">or</span> entry <span style="color: #AA22FF; font-weight: bold">is</span> key:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> entry<br /> free <span style="color: #666666">=</span> <span style="color: #AA22FF">None</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">is</span> dummy:<br /> free <span style="color: #666666">=</span> entry<br /> <span style="color: #AA22FF; font-weight: bold">elif</span> entry<span style="color: #666666">.</span>hash <span style="color: #666666">==</span> key_hash <span style="color: #AA22FF; font-weight: bold">and</span> key <span style="color: #666666">==</span> entry<span style="color: #666666">.</span>key:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> entry<br /><br /> perturb <span style="color: #666666">=</span> key_hash<br /> <span style="color: #AA22FF; font-weight: bold">while</span> <span style="color: #AA22FF">True</span>:<br /> i <span style="color: #666666">=</span> (i <span style="color: #666666"><<</span> <span style="color: #666666">2</span>) <span style="color: #666666">+</span> i <span style="color: #666666">+</span> perturb <span style="color: #666666">+</span> <span style="color: #666666">1</span>;<br /> entry <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table[i <span style="color: #666666">&</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask]<br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> entry <span style="color: #AA22FF; font-weight: bold">if</span> free <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span> <span style="color: #AA22FF; font-weight: bold">else</span> free<br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">is</span> key <span style="color: #AA22FF; font-weight: bold">or</span> \<br /> (entry<span style="color: #666666">.</span>hash <span style="color: #666666">==</span> key_hash <span style="color: #AA22FF; font-weight: bold">and</span> key <span style="color: #666666">==</span> entry<span style="color: #666666">.</span>key):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> entry<br /> <span style="color: #AA22FF; font-weight: bold">elif</span> entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">is</span> dummy <span style="color: #AA22FF; font-weight: bold">and</span> free <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> free <span style="color: #666666">=</span> dummy<br /> perturb <span style="color: #666666">>>=</span> PERTURB_SHIFT<br /><br /> <span style="color: #AA22FF; font-weight: bold">assert</span> <span style="color: #AA22FF">False</span>, <span style="color: #BB4444">"not reached"</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_resize</span>(<span style="color: #AA22FF">self</span>, minused):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Resize the dictionary to at least minused.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> newsize <span style="color: #666666">=</span> MINSIZE<br /> <span style="color: #008800; font-style: italic"># Find the smalled value for newsize.</span><br /> <span style="color: #AA22FF; font-weight: bold">while</span> newsize <span style="color: #666666"><=</span> minused <span style="color: #AA22FF; font-weight: bold">and</span> newsize <span style="color: #666666">></span> <span style="color: #666666">0</span>:<br /> newsize <span style="color: #666666"><<=</span> <span style="color: #666666">1</span><br /> oldtable <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table<br /> <span style="color: #008800; font-style: italic"># Create a new table newsize long.</span><br /> newtable <span style="color: #666666">=</span> []<br /> <span style="color: #AA22FF; font-weight: bold">while</span> <span style="color: #AA22FF">len</span>(newtable) <span style="color: #666666"><</span> newsize:<br /> newtable<span style="color: #666666">.</span>append(Entry())<br /> <span style="color: #008800; font-style: italic"># Replace the old table.</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table <span style="color: #666666">=</span> newtable<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">=</span> <span style="color: #666666">0</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>filled <span style="color: #666666">=</span> <span style="color: #666666">0</span><br /> <span style="color: #008800; font-style: italic"># Copy the old data into the new table.</span><br /> <span style="color: #AA22FF; font-weight: bold">for</span> entry <span style="color: #AA22FF; font-weight: bold">in</span> oldtable:<br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_insert_into_clean(entry)<br /> <span style="color: #AA22FF; font-weight: bold">elif</span> entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">is</span> dummy:<br /> entry<span style="color: #666666">.</span>key <span style="color: #666666">=</span> <span style="color: #AA22FF">None</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask <span style="color: #666666">=</span> newsize <span style="color: #666666">-</span> <span style="color: #666666">1</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_insert_into_clean</span>(<span style="color: #AA22FF">self</span>, entry):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Insert an item in a clean dict. This is a helper for resizing.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> i <span style="color: #666666">=</span> entry<span style="color: #666666">.</span>hash <span style="color: #666666">&</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask<br /> new_entry <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table[i]<br /> perturb <span style="color: #666666">=</span> entry<span style="color: #666666">.</span>hash<br /> <span style="color: #AA22FF; font-weight: bold">while</span> new_entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span>:<br /> i <span style="color: #666666">=</span> (i <span style="color: #666666"><<</span> <span style="color: #666666">2</span>) <span style="color: #666666">+</span> i <span style="color: #666666">+</span> perturb <span style="color: #666666">+</span> <span style="color: #666666">1</span><br /> new_entry <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table[i <span style="color: #666666">&</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask]<br /> perturb <span style="color: #666666">>>=</span> PERTURB_SHIFT<br /> new_entry<span style="color: #666666">.</span>key <span style="color: #666666">=</span> entry<span style="color: #666666">.</span>key<br /> new_entry<span style="color: #666666">.</span>value <span style="color: #666666">=</span> entry<span style="color: #666666">.</span>value<br /> new_entry<span style="color: #666666">.</span>hash <span style="color: #666666">=</span> entry<span style="color: #666666">.</span>hash<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">+=</span> <span style="color: #666666">1</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>filled <span style="color: #666666">+=</span> <span style="color: #666666">1</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_insert</span>(<span style="color: #AA22FF">self</span>, key, value):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Add a new value to the dictionary or replace an old one.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> entry <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_lookup(key)<br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">+=</span> <span style="color: #666666">1</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> dummy:<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>filled <span style="color: #666666">+=</span> <span style="color: #666666">1</span><br /> entry<span style="color: #666666">.</span>key <span style="color: #666666">=</span> key<br /> entry<span style="color: #666666">.</span>hash <span style="color: #666666">=</span> <span style="color: #AA22FF">hash</span>(key)<br /> entry<span style="color: #666666">.</span>value <span style="color: #666666">=</span> value<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_del</span>(<span style="color: #AA22FF">self</span>, entry):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Mark an entry as free with the dummy key.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> entry<span style="color: #666666">.</span>key <span style="color: #666666">=</span> dummy<br /> entry<span style="color: #666666">.</span>value <span style="color: #666666">=</span> <span style="color: #AA22FF">None</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">-=</span> <span style="color: #666666">1</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__getitem__</span>(<span style="color: #AA22FF">self</span>, key):<br /> value <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_lookup(key)<span style="color: #666666">.</span>value<br /> <span style="color: #AA22FF; font-weight: bold">if</span> value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #008800; font-style: italic"># Check if we're a subclass.</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF">type</span>(<span style="color: #AA22FF">self</span>) <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> Dict:<br /> <span style="color: #008800; font-style: italic"># Try to call the __missing__ method.</span><br /> missing <span style="color: #666666">=</span> <span style="color: #AA22FF">getattr</span>(<span style="color: #AA22FF">self</span>, <span style="color: #BB4444">"__missing__"</span>)<br /> <span style="color: #AA22FF; font-weight: bold">if</span> missing <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> missing(key)<br /> <span style="color: #AA22FF; font-weight: bold">raise</span> <span style="color: #D2413A; font-weight: bold">KeyError</span>(<span style="color: #BB4444">"no such key: {0!r}"</span><span style="color: #666666">.</span>format(key))<br /> <span style="color: #AA22FF; font-weight: bold">return</span> value<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__setitem__</span>(<span style="color: #AA22FF">self</span>, key, what):<br /> <span style="color: #008800; font-style: italic"># None is used as a marker for empty entries, so it can't be in a</span><br /> <span style="color: #008800; font-style: italic"># dictionary.</span><br /> <span style="color: #AA22FF; font-weight: bold">assert</span> what <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span> <span style="color: #AA22FF; font-weight: bold">and</span> key <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span>, \<br /> <span style="color: #BB4444">"key and value must not be None"</span><br /> old_used <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_insert(key, what)<br /> <span style="color: #008800; font-style: italic"># Maybe resize the dict.</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF; font-weight: bold">not</span> (<span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">></span> old_used <span style="color: #AA22FF; font-weight: bold">and</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>filled<span style="color: #666666">*3</span> <span style="color: #666666">>=</span> (<span style="color: #AA22FF">self</span><span style="color: #666666">.</span>mask <span style="color: #666666">+</span> <span style="color: #666666">1</span>)<span style="color: #666666">*2</span>):<br /> <span style="color: #AA22FF; font-weight: bold">return</span><br /> <span style="color: #008800; font-style: italic"># Large dictionaries (< 5000) are only doubled in size.</span><br /> factor <span style="color: #666666">=</span> <span style="color: #666666">2</span> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">></span> <span style="color: #666666">5000</span> <span style="color: #AA22FF; font-weight: bold">else</span> <span style="color: #666666">4</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_resize(factor<span style="color: #666666">*</span><span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__delitem__</span>(<span style="color: #AA22FF">self</span>, key):<br /> entry <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_lookup(key)<br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #AA22FF; font-weight: bold">raise</span> <span style="color: #D2413A; font-weight: bold">KeyError</span>(<span style="color: #BB4444">"no such key: {0!r}"</span><span style="color: #666666">.</span>format(key))<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_del(entry)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__contains__</span>(<span style="color: #AA22FF">self</span>, key):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Check if a key is in the dictionary.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_lookup(key)<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__eq__</span>(<span style="color: #AA22FF">self</span>, other):<br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">isinstance</span>(other, Dict):<br /> <span style="color: #AA22FF; font-weight: bold">try</span>:<br /> <span style="color: #008800; font-style: italic"># Try to coerce the other to a Dict, so we can compare it.</span><br /> other <span style="color: #666666">=</span> Dict(other)<br /> <span style="color: #AA22FF; font-weight: bold">except</span> <span style="color: #D2413A; font-weight: bold">TypeError</span>:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">NotImplemented</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">!=</span> other<span style="color: #666666">.</span>used:<br /> <span style="color: #008800; font-style: italic"># They're not the same size.</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">False</span><br /> <span style="color: #008800; font-style: italic"># Look through the table and compare every entry, breaking out early if</span><br /> <span style="color: #008800; font-style: italic"># we find a difference.</span><br /> <span style="color: #AA22FF; font-weight: bold">for</span> entry <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table:<br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span>:<br /> <span style="color: #AA22FF; font-weight: bold">try</span>:<br /> bval <span style="color: #666666">=</span> other[entry<span style="color: #666666">.</span>key]<br /> <span style="color: #AA22FF; font-weight: bold">except</span> <span style="color: #D2413A; font-weight: bold">KeyError</span>:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">False</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF; font-weight: bold">not</span> bval <span style="color: #666666">==</span> entry<span style="color: #666666">.</span>value:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">False</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">True</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__ne__</span>(<span style="color: #AA22FF">self</span>, other):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">self</span> <span style="color: #666666">==</span> other<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">keys</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Return a list of keys in the dictionary.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> [entry<span style="color: #666666">.</span>key <span style="color: #AA22FF; font-weight: bold">for</span> entry <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span>]<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">values</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Return a list of values in the dictionary.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> [entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">for</span> entry <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span>]<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">items</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Return a list of key-value pairs.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> [(entry<span style="color: #666666">.</span>key, entry<span style="color: #666666">.</span>value) <span style="color: #AA22FF; font-weight: bold">for</span> entry <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>table<br /> <span style="color: #AA22FF; font-weight: bold">if</span> entry<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF; font-weight: bold">not</span> <span style="color: #AA22FF">None</span>]<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__iter__</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> DictKeysIterator(<span style="color: #AA22FF">self</span>)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">itervalues</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Return an iterator over the values in the dictionary.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> DictValuesIterator(<span style="color: #AA22FF">self</span>)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">iterkeys</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Return an iterator over the keys in the dictionary.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> DictKeysIterator(<span style="color: #AA22FF">self</span>)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">iteritems</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Return an iterator over key-value pairs.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> DictItemsIterator(<span style="color: #AA22FF">self</span>)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_merge</span>(<span style="color: #AA22FF">self</span>, mapping):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Update the dictionary from a mapping.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">for</span> key <span style="color: #AA22FF; font-weight: bold">in</span> mapping<span style="color: #666666">.</span>keys():<br /> <span style="color: #AA22FF">self</span>[key] <span style="color: #666666">=</span> mapping[key]<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_from_sequence</span>(<span style="color: #AA22FF">self</span>, seq):<br /> <span style="color: #AA22FF; font-weight: bold">for</span> double <span style="color: #AA22FF; font-weight: bold">in</span> seq:<br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF">len</span>(double) <span style="color: #666666">!=</span> <span style="color: #666666">2</span>:<br /> <span style="color: #AA22FF; font-weight: bold">raise</span> <span style="color: #D2413A; font-weight: bold">ValueError</span>(<span style="color: #BB4444">"{0!r} doesn't have a length of 2"</span><span style="color: #666666">.</span>format(<br /> double))<br /> <span style="color: #AA22FF">self</span>[double[<span style="color: #666666">0</span>]] <span style="color: #666666">=</span> double[<span style="color: #666666">1</span>]<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_update</span>(<span style="color: #AA22FF">self</span>, arg, kwargs):<br /> <span style="color: #AA22FF; font-weight: bold">if</span> arg:<br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF">isinstance</span>(arg, collections<span style="color: #666666">.</span>Mapping):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_merge(arg)<br /> <span style="color: #AA22FF; font-weight: bold">else</span>:<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_from_sequence(arg)<br /> <span style="color: #AA22FF; font-weight: bold">if</span> kwargs:<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_merge(kwargs)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">update</span>(<span style="color: #AA22FF">self</span>, arg<span style="color: #666666">=</span><span style="color: #AA22FF">None</span>, <span style="color: #666666">**</span>kwargs):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Update the dictionary from a mapping or sequence containing key-value</span><br /><span style="color: #BB4444; font-style: italic"> pairs. Any existing values are overwritten.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_update(arg, kwargs)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">get</span>(<span style="color: #AA22FF">self</span>, key, default<span style="color: #666666">=0</span>):<br /> <span style="color: #BB4444; font-style: italic">"""</span><br /><span style="color: #BB4444; font-style: italic"> Return the value for key if it exists otherwise the default.</span><br /><span style="color: #BB4444; font-style: italic"> """</span><br /> <span style="color: #AA22FF; font-weight: bold">try</span>:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">self</span>[key]<br /> <span style="color: #AA22FF; font-weight: bold">except</span> <span style="color: #D2413A; font-weight: bold">KeyError</span>:<br /> <span style="color: #AA22FF; font-weight: bold">return</span> default<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__len__</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__repr__</span>(<span style="color: #AA22FF">self</span>):<br /> r <span style="color: #666666">=</span> [<span style="color: #BB4444">"{0!r} : {1!r}"</span><span style="color: #666666">.</span>format(k, v) <span style="color: #AA22FF; font-weight: bold">for</span> k, v <span style="color: #AA22FF; font-weight: bold">in</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>iteritems()]<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #BB4444">"Dict({"</span> <span style="color: #666666">+</span> <span style="color: #BB4444">", "</span><span style="color: #666666">.</span>join(r) <span style="color: #666666">+</span> <span style="color: #BB4444">"})"</span><br /><br />collections<span style="color: #666666">.</span>Mapping<span style="color: #666666">.</span>register(Dict)<br /><br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">DictIterator</span>(<span style="color: #AA22FF">object</span>):<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__init__</span>(<span style="color: #AA22FF">self</span>, d):<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>d <span style="color: #666666">=</span> d<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>d<span style="color: #666666">.</span>used<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>len <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>d<span style="color: #666666">.</span>used<br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>pos <span style="color: #666666">=</span> <span style="color: #666666">0</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__iter__</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">self</span><br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">next</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #008800; font-style: italic"># Check if the dictionary has been mutated under us.</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">!=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>d<span style="color: #666666">.</span>used:<br /> <span style="color: #008800; font-style: italic"># Make this state permanent.</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>used <span style="color: #666666">=</span> <span style="color: #666666">-1</span><br /> <span style="color: #AA22FF; font-weight: bold">raise</span> <span style="color: #D2413A; font-weight: bold">RuntimeError</span>(<span style="color: #BB4444">"dictionary size changed during interation"</span>)<br /> i <span style="color: #666666">=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>pos<br /> <span style="color: #AA22FF; font-weight: bold">while</span> i <span style="color: #666666"><=</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>d<span style="color: #666666">.</span>mask <span style="color: #AA22FF; font-weight: bold">and</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>d<span style="color: #666666">.</span>table[i]<span style="color: #666666">.</span>value <span style="color: #AA22FF; font-weight: bold">is</span> <span style="color: #AA22FF">None</span>:<br /> i <span style="color: #666666">+=</span> <span style="color: #666666">1</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>pos <span style="color: #666666">=</span> i <span style="color: #666666">+</span> <span style="color: #666666">1</span><br /> <span style="color: #AA22FF; font-weight: bold">if</span> i <span style="color: #666666">></span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>d<span style="color: #666666">.</span>mask:<br /> <span style="color: #008800; font-style: italic"># We're done.</span><br /> <span style="color: #AA22FF; font-weight: bold">raise</span> <span style="color: #D2413A; font-weight: bold">StopIteration</span><br /> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>len <span style="color: #666666">-=</span> <span style="color: #666666">1</span><br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>_extract(<span style="color: #AA22FF">self</span><span style="color: #666666">.</span>d<span style="color: #666666">.</span>table[i])<br /><br /> __next__ <span style="color: #666666">=</span> next<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_extract</span>(<span style="color: #AA22FF">self</span>, entry):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">getattr</span>(entry, <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>kind)<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">__len__</span>(<span style="color: #AA22FF">self</span>):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> <span style="color: #AA22FF">self</span><span style="color: #666666">.</span>len<br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">DictKeysIterator</span>(DictIterator):<br /> kind <span style="color: #666666">=</span> <span style="color: #BB4444">"key"</span><br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">DictValuesIterator</span>(DictIterator):<br /> kind <span style="color: #666666">=</span> <span style="color: #BB4444">"value"</span><br /><br /><span style="color: #AA22FF; font-weight: bold">class</span> <span style="color: #0000FF">DictItemsIterator</span>(DictIterator):<br /><br /> <span style="color: #AA22FF; font-weight: bold">def</span> <span style="color: #00A000">_extract</span>(<span style="color: #AA22FF">self</span>, entry):<br /> <span style="color: #AA22FF; font-weight: bold">return</span> entry<span style="color: #666666">.</span>key, entry<span style="color: #666666">.</span>value<br /></pre></div>Unknownnoreply@blogger.com8tag:blogger.com,1999:blog-8671476328661520656.post-78251617056967375712008-10-13T14:55:00.002-07:002008-10-13T15:15:47.140-07:00First impressions of darcsThis week, I've been playing around with the relatively little known distributed version control system, <a href="http://darcs.net">darcs</a>. (That stands for David's Advanced Revision Control System.)<br /><br />Darcs is based on David Roundy's, its creator, <a href="http://darcs.net/manual/node9.html">theory of patches</a>. Simply put, darcs' fundamental type is a difference between two trees, a patch.<br /><br />Creating a simple repo was quick and painless with "darcs initialize". I recorded a few patches easily, and was feeling quite happy about the fast pace with which darcs went about its business. Then, I decided to review my work. Apparently, darcs has no concept of a revision number; every "commit" is just a patch. This makes selecting patches to review rather difficult since everything is relative to the current state of the repo. Perhaps this isn't a problem in practice, though, because advanced patch matching (with regular expressions) is provided. Another thing I disliked was the lack of history in merging between repos. Although it is simple to do, no evidence besides the author's name in the log indicates that the patch was pulled.<br /><br />Obviously, this is just a first step into the exciting darcs world; I'll continue to use it for some of my projects, and report back later.Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-8671476328661520656.post-41749623248252829792008-10-01T15:10:00.000-07:002008-10-02T04:49:19.323-07:00Python 2.6 released!Fire the cannons! Begin the fireworks! Scream at the top of your lungs! Clink your glasses! Python 2.6 is here! <a href="http://python.org/download/">Download it</a>, and <a href="http://doc.python.org/whatsnew/2.6.html">learn what's new</a>.<br /><br />This is my first final python release on the core team, and I'm quite proud of our baby. :)Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8671476328661520656.post-10253471695894021222008-09-14T19:29:00.000-07:002008-09-14T19:46:16.154-07:002.6 RC 1 is outIf you didn't already know it, 2.6 RC 1 <a href="http://mail.python.org/pipermail/python-dev/2008-September/082357.html">was released</a> two days ago. There's nothing big to report (and there shouldn't be of course!). In fact, the biggest change you may notice is the absence of a 3.0 RC alongside. This is due to the fact that <a href="http://mail.python.org/pipermail/python-dev/2008-September/082315.html">we believe</a> although 2.6 is almost rock solid, 3.0 definitely still needs some more TLC. We are still aiming for a 2.6 final on October 1st, but 3.0 has been pushed back to the 15th. (You can, of course, see the whole release schedule in <a href="http://www.python.org/dev/peps/pep-0361/">PEP 361</a>.) Please, please, please take the time to <a href="http://www.python.org/download/releases/2.6/">download it</a> and test it with your project; <emp>now</emp> is when we want to know about grotesque bugs and incompatibilities!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8671476328661520656.post-9812213622144044322008-09-04T14:08:00.000-07:002008-09-04T19:22:29.669-07:00Fun with 2to3Recently, I've been working on <a href="http://svn.python.org/view/sandbox/trunk/2to3/">2to3</a> code refactoring tool. It's quite exciting really; how often does automatic editing of source code work?<br /><br />2to3 is completely written in Python using the stdlib. The main steps in code translation are:<br /><ol><br /><li>2to3 is given a Python source file and a list of transformations (in units called fixers) to apply to it.</li><br /><li>2to3 generates a custom parse tree of the source based on a Python grammar that combines elements of 2.x and 3.x's syntax. It takes note of exact indentation and comment so it will be reproduced exactly later.</li><br /><li>Each fixer has a pattern that describes the nodes it wants to match in the parse tree. The tree is traversed while asking each fixer if it matches the given node.</li><br /><li>If the fixer's pattern matches the node, the fixer is ask to transform the code. The fixer can manipulate the parse tree directly.</li><br /><li>A diff against the original source is printed to stdout and optionally written back to the file.</li><br /></ol><br /><br />Over the past few weeks, I've written a couple of fixers. It's pretty intuitive once you get the hang of it, but writing <a href="http://svn.python.org/view/sandbox/trunk/2to3/lib2to3/tests/test_fixers.py?view=markup">good tests</a> is very important because Python's flexible syntax produces many possibilities you fixer must deal with. I also <a href="http://svn.python.org/view/sandbox/trunk/2to3/lib2to3/main.py?rev=66173&view=rev">refactored lib2to3</a>, so plugging a different system of fixers is much easier for custom applications. I've also written some <a href="http://doc.python.org/dev/library/2to3.html">documentation on it's usage</a>. I hope to start documenting the API and writing a guide for creating fixers soon, so other people can start making use of lib2to3.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-8671476328661520656.post-77574832937985666642008-09-04T14:01:00.000-07:002008-09-04T14:07:51.203-07:00On the Google Open Source BlogIt seems my testing project has made the <a href="http://google-opensource.blogspot.com/2008/09/testing-cpython-core.html">Google Open Source Blog</a>! Once again, I'd like to give a huge round of applause everyone who made it possible!Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-8671476328661520656.post-3777625171524732422008-08-21T06:25:00.000-07:002008-09-03T15:20:05.710-07:00The third betas are out!Last night, <a href="http://mail.python.org/pipermail/python-announce-list/2008-August/006827.html">Barry released</a> the third and final betas for Python 2.6 and 3.0. This release really saw a monumental effort from everyone. Tuesday was filled with coding, code reviews, and bug fixes, and we were able to close all 10 release blockers. It was looking very bright for a release yesterday morning. (Including the fantastic omen of a green Windows buildbot.) That didn't stop <a href="http://bugs.python.org/3611">another release blocker</a> from popping up hours before the release. However, we were able to get that one fixed due to some excellent debugging on the parts of Amaury Forgeot d'Arc, Antoine Pitrou, and Victor Stinner. Highlights:<br /><ul><br /><li>A more completed memoryview implementation. (Once again <a href="http://mail.python.org/pipermail/python-dev/2008-August/081914.html">thanks to</a> Antoine.</li><br /><li>I fixed up the symtable module and wrote unittests and <a href="http://doc.python.org/dev/library/symtable.rst">docs</a> for it. It should actually be functional now...</li><br /><li>The threading API was renamed once again. Now daemon, and name are properties of the Thread object. (That's the last time I'm doing threading renaming I assure you!)</li><br /><li>multiprocessing has gotten more stable.</li><br /><li>Guido donated the SRE bytecode validator he wrote for the App Engine.</li><br /><li>Many, many, many little bug fixes.</li><br /></ul><br /><br />Of course, there's still lots of work to do before we can get to release candidates. Hours after the release we already have <a href="http://bugs.python.org/issue?@columns=title,id,activity,versions,status&@sort=activity&@filter=priority,status&@pagesize=50&@startwith=0&priority=1&status=1&@dispname=Showstoppers">11 release blockers</a>. In the mean time, I strongly encourage you to download <a href="http://www.python.org/download/releases/2.6/">2.6</a> and <a href="http://www.python.org/download/releases/3.0/">3.0</a> and test them with your project. The bug tracker is still there: <a href="http://bugs.python.org">http://bugs.python.org</a>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-8671476328661520656.post-54477796919902299932008-07-25T09:02:00.000-07:002008-07-25T09:37:26.458-07:00bzr vs. hg -- a different perspectiveI'd say one of my favorite parts of F/OSS is the educational value I can get from it. There's much more practical programming knowledge in Python/import.c than in your average CS textbook.<br /><br />My code curiosity recently turned to my favorite (D)VCSes, <a href="http://selenic.com/mercurial">Mercurial</a>, and <a href="http://bazaar-vcs.org">Bazaar</a>. (I've tried reading Subversion, but the C is just too much.) Much of the world (including me) likes to battle over their merits, but I'd like to talk about what I saw in the source. (<emp>Disclaimer:</emp> I do not claim to have an good knowledge of either project's design philosophy or why things were done the way they were.)<br /><br />On the superficial side, Bazaar has a lot more code than Mercurial does: About 1 MB with 2.5 MB of tests for Mercurial and 6MB with 6 MB of tests for Bazaar. I'm not going to make anything of it, though, for fear of condemnation. Mercurial's non-capitalized class names also drive me a bit crazy...<br /><br />Overall, Mercurial appears to be a much simpler system, true to the wisdom of "do one thing well". The one repository format is beautifully simple. Bazaar, on the other hand, has to have layers of abstraction in order to make access over many protocols and different repository, branch, and working tree formats possible. For this complexity, it gains much flexibility allowing it to be a hybrid distributed and central VCS. Bazaar's source code also has many more comments and docstrings. Mercurial's looks rather bare in comparison.<br /><br />Bazaar and Mercurial both seem to implement dirstate the same way. They also both have C extensions targeted to speed themselves up.<br /><br />In the end, the both work well and are a pleasure to use, so I'm not going to complain.Unknownnoreply@blogger.com0