Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Site updated at 2013-05-07 16:05:58 UTC

  • Loading branch information...
commit 77f8a0d9ebf2b0ba6bf98ddac32c373d7d6775be 1 parent 66b01a1
@dcramer authored
Showing with 1,754 additions and 1,475 deletions.
  1. +208 −0 2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt/index.html
  2. +23 −1 archives/index.html
  3. +72 −96 atom.xml
  4. +25 −1 blog/archives/index.html
  5. +32 −30 blog/page/10/index.html
  6. +30 −42 blog/page/11/index.html
  7. +42 −68 blog/page/12/index.html
  8. +68 −34 blog/page/13/index.html
  9. +34 −34 blog/page/14/index.html
  10. +34 −44 blog/page/15/index.html
  11. +44 −40 blog/page/16/index.html
  12. +40 −1 blog/page/17/index.html
  13. +159 −123 blog/page/2/index.html
  14. +123 −96 blog/page/3/index.html
  15. +96 −86 blog/page/4/index.html
  16. +86 −36 blog/page/5/index.html
  17. +36 −42 blog/page/6/index.html
  18. +42 −78 blog/page/7/index.html
  19. +78 −36 blog/page/8/index.html
  20. +36 −32 blog/page/9/index.html
  21. +1 −1  categories/ci/atom.xml
  22. +1 −1  categories/disqus/atom.xml
  23. +92 −183 categories/django/atom.xml
  24. +24 −0 categories/django/index.html
  25. +1 −1  categories/git/atom.xml
  26. +1 −1  categories/heroku/atom.xml
  27. +1 −1  categories/howto/atom.xml
  28. +1 −1  categories/ops/atom.xml
  29. +1 −1  categories/osx/atom.xml
  30. +1 −1  categories/postgresql/atom.xml
  31. +1 −1  categories/python/atom.xml
  32. +1 −1  categories/sentry/atom.xml
  33. +1 −1  categories/solr/atom.xml
  34. +1 −1  disqus.xml
  35. +19 −15 django.xml
  36. +1 −1  feeds/disqus.xml
  37. +19 −15 feeds/django.xml
  38. +102 −159 index.html
  39. +176 −169 sitemap.xml
  40. +1 −1  stylesheets/screen.css
View
208 2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt/index.html
@@ -0,0 +1,208 @@
+
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Making Django 1.5 compatible with django-bcrypt - David Cramer's Blog</title>
+ <meta name="author" content="David Cramer">
+
+
+ <meta name="description" content="Making Django 1.5 Compatible With Django-bcrypt Last night I took the opportunity to upgrade all of getsentry.com to
+Django 1.5. While most things &hellip;">
+
+ <meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
+
+ <link href="http://feeds.feedburner.com/DavidCramernet" rel="alternate" title="David Cramer's Blog" type="application/atom+xml">
+ <link rel="canonical" href="">
+ <link href="/favicon.png" rel="shortcut icon">
+ <link href="/stylesheets/screen.css?1" media="screen, projection" rel="stylesheet" type="text/css">
+ <!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ <script type="text/javascript">
+ var _gauges = _gauges || [];
+ (function() {
+ var t = document.createElement('script');
+ t.type = 'text/javascript';
+ t.async = true;
+ t.id = 'gauges-tracker';
+ t.setAttribute('data-site-id', '4f0ffdc0844d521595000001');
+ t.src = '//secure.gaug.es/track.js';
+ var s = document.getElementsByTagName('script')[0];
+ s.parentNode.insertBefore(t, s);
+ })();
+</script>
+
+
+</head>
+
+<body>
+ <header class="inner">
+ <div class="container">
+ <h1><a href="/">David Cramer's Blog</a></h1>
+<nav class="menu"><ul class="main">
+ <li><a href="/">Blog</a></li>
+ <li><a href="/blog/archives">Archives</a></li>
+</ul>
+</nav>
+<div class="right">
+ <form class="search right" action="http://google.com/search" method="get">
+ <input class="left" type="text" name="q" results="0">
+ <input type="hidden" name="q" value="site:justcramer.com">
+ </form>
+ <div class="social right">
+
+
+
+ <a class="twitter" href="http://twitter.com/zeeg" title="Twitter">Twitter</a>
+
+
+ <a class="github" href="https://github.com/dcramer" title="GitHub">GitHub</a>
+
+
+
+ <a class="rss" href="http://feeds.feedburner.com/DavidCramernet" title="RSS">RSS</a>
+
+ </div>
+</div>
+
+
+ </div>
+ </header>
+ <div id="content" class="inner"><article class="post">
+ <h1 class="title">Making Django 1.5 Compatible With Django-bcrypt</h1>
+ <div class="entry"><p>Last night I took the opportunity to upgrade all of <a href="https://getsentry.com">getsentry.com</a> to
+Django 1.5. While most things were fairly trivial to sort out, we hit one less obvious (and pretty critical) bug
+during the migration surrounding <a href="https://github.com/dwaiter/django-bcrypt">django-bcrypt</a>.</p>
+
+<p>This bug would only present itself if you&#8217;ve transitioned from older versions of Django, and therefore have passwords
+in the database using the custom algorithm. Specifically, you&#8217;ll have passwords in your user&#8217;s table that look something
+like <code>bc$$somestring$12$somestring</code>.</p>
+
+<p>The fix is actually fairly simple, and just requires you to define a slightly custom legacy backend for django-bcrypt:</p>
+
+<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
+<span class='line-number'>2</span>
+<span class='line-number'>3</span>
+<span class='line-number'>4</span>
+<span class='line-number'>5</span>
+<span class='line-number'>6</span>
+<span class='line-number'>7</span>
+<span class='line-number'>8</span>
+<span class='line-number'>9</span>
+<span class='line-number'>10</span>
+<span class='line-number'>11</span>
+<span class='line-number'>12</span>
+<span class='line-number'>13</span>
+<span class='line-number'>14</span>
+<span class='line-number'>15</span>
+<span class='line-number'>16</span>
+</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="kn">from</span> <span class="nn">django.contrib.auth.hashers</span> <span class="kn">import</span> <span class="n">BCryptPasswordHasher</span>
+</span><span class='line'><span class="kn">from</span> <span class="nn">django.utils.crypto</span> <span class="kn">import</span> <span class="n">constant_time_compare</span>
+</span><span class='line'><span class="kn">from</span> <span class="nn">django.utils.encoding</span> <span class="kn">import</span> <span class="n">force_bytes</span>
+</span><span class='line'>
+</span><span class='line'>
+</span><span class='line'><span class="k">class</span> <span class="nc">DjangoBCryptPasswordHasher</span><span class="p">(</span><span class="n">BCryptPasswordHasher</span><span class="p">):</span>
+</span><span class='line'> <span class="sd">&quot;&quot;&quot;</span>
+</span><span class='line'><span class="sd"> Handles legacy passwords wich were hashed with the &#39;bc$&#39; algorithm via</span>
+</span><span class='line'><span class="sd"> django-bcrypt.</span>
+</span><span class='line'><span class="sd"> &quot;&quot;&quot;</span>
+</span><span class='line'> <span class="n">algorithm</span> <span class="o">=</span> <span class="s">&quot;bc&quot;</span>
+</span><span class='line'>
+</span><span class='line'> <span class="k">def</span> <span class="nf">verify</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">password</span><span class="p">,</span> <span class="n">encoded</span><span class="p">):</span>
+</span><span class='line'> <span class="n">data</span> <span class="o">=</span> <span class="n">encoded</span><span class="p">[</span><span class="mi">3</span><span class="p">:]</span>
+</span><span class='line'> <span class="n">bcrypt</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_load_library</span><span class="p">()</span>
+</span><span class='line'> <span class="k">return</span> <span class="n">constant_time_compare</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">bcrypt</span><span class="o">.</span><span class="n">hashpw</span><span class="p">(</span><span class="n">force_bytes</span><span class="p">(</span><span class="n">password</span><span class="p">),</span> <span class="n">data</span><span class="p">))</span>
+</span></code></pre></td></tr></table></div></figure>
+
+<p>Once you&#8217;ve defined the backend, the rest is as simple as adding it to your list of password hashers:</p>
+
+<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
+<span class='line-number'>2</span>
+<span class='line-number'>3</span>
+<span class='line-number'>4</span>
+<span class='line-number'>5</span>
+<span class='line-number'>6</span>
+<span class='line-number'>7</span>
+<span class='line-number'>8</span>
+</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">PASSWORD_HASHERS</span> <span class="o">=</span> <span class="p">(</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.PBKDF2PasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.BCryptPasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;getsentry.utils.auth.DjangoBCryptPasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.SHA1PasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.MD5PasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'><span class="p">)</span>
+</span></code></pre></td></tr></table></div></figure>
+</div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2013-05-07T08:43:00-07:00" pubdate data-updated="true">May 7<span>th</span>, 2013</time></div>
+ <div class="tags">
+
+<div class="cat">
+
+ <a class='category' href='/categories/django/'>django</a>
+
+</div>
+
+</div>
+
+ <span class="comments"><a href="#disqus_thread">Comments</a></span>
+
+ </div>
+</article>
+<div class="share">
+ <div class="addthis_toolbox addthis_default_style ">
+
+
+ <a class="addthis_button_tweet"></a>
+
+
+ <a class="addthis_counter addthis_pill_style"></a>
+ </div>
+ <script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid="></script>
+</div>
+
+
+<section id="comment">
+ <h1 class="title">Comments</h1>
+ <div id="disqus_thread" aria-live="polite"><noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
+</div>
+</section>
+</div>
+ <footer class="inner">Copyright &copy; 2013 David Cramer &mdash; Need exceptional error logging? Try out <a href="https://www.getsentry.com">Sentry</a></footer>
+ <script src="/javascripts/jquery.fancybox.pack.js"></script>
+<script src="/javascripts/slash.js"></script>
+
+
+<script type="text/javascript">
+ var disqus_shortname = 'davidcramer';
+
+
+ // var disqus_developer = 1;
+ var disqus_identifier = 'http://justcramer.com/2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt';
+ var disqus_url = 'http://justcramer.com/2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt';
+ var disqus_script = 'embed.js';
+
+ (function () {
+ var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
+ dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+ }());
+</script>
+
+
+
+</body>
+</html>
View
24 archives/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="Blog Archive 2013 A Weekend In Russia Feb 27 django, python Comments Moving On Feb 11 Comments Dependency Graphs and Package Versioning Jan 29 &hellip;">
+ <meta name="description" content="Blog Archive 2013 Making Django 1.5 compatible with django-bcrypt May 7 django Comments A Weekend In Russia Feb 27 django, python Comments Moving On &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -80,6 +80,28 @@ <h1 class="title">Blog Archive</h1>
<article>
+<h1 class="title"><a href="/2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt">Making Django 1.5 compatible with django-bcrypt</a></h1>
+<div class="meta">
+ <span class="date">May 7</span>
+ <span class="tags">
+
+<div class="cat">
+
+ <a class='category' href='/categories/django/'>django</a>
+
+</div>
+
+</span>
+
+ <span class="comments"><a href="/2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt#disqus_thread">Comments</a></span>
+
+</div>
+</article>
+
+
+
+<article>
+
<h1 class="title"><a href="/2013/02/27/a-weekend-in-russia">A Weekend In Russia</a></h1>
<div class="meta">
<span class="date">Feb 27</span>
View
168 atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[David Cramer's Blog]]></title>
<link href="http://justcramer.com/atom.xml" rel="self"/>
<link href="http://justcramer.com/"/>
- <updated>2013-03-02T16:06:11-08:00</updated>
+ <updated>2013-05-07T09:02:13-07:00</updated>
<id>http://justcramer.com/</id>
<author>
<name><![CDATA[David Cramer]]></name>
@@ -14,6 +14,77 @@
<entry>
+ <title type="html"><![CDATA[Making Django 1.5 compatible with django-bcrypt]]></title>
+ <link href="http://justcramer.com/2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt"/>
+ <updated>2013-05-07T08:43:00-07:00</updated>
+ <id>http://justcramer.com/2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt</id>
+ <content type="html"><![CDATA[<p>Last night I took the opportunity to upgrade all of <a href="https://getsentry.com">getsentry.com</a> to
+Django 1.5. While most things were fairly trivial to sort out, we hit one less obvious (and pretty critical) bug
+during the migration surrounding <a href="https://github.com/dwaiter/django-bcrypt">django-bcrypt</a>.</p>
+
+<p>This bug would only present itself if you&#8217;ve transitioned from older versions of Django, and therefore have passwords
+in the database using the custom algorithm. Specifically, you&#8217;ll have passwords in your user&#8217;s table that look something
+like <code>bc$$somestring$12$somestring</code>.</p>
+
+<p>The fix is actually fairly simple, and just requires you to define a slightly custom legacy backend for django-bcrypt:</p>
+
+<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
+<span class='line-number'>2</span>
+<span class='line-number'>3</span>
+<span class='line-number'>4</span>
+<span class='line-number'>5</span>
+<span class='line-number'>6</span>
+<span class='line-number'>7</span>
+<span class='line-number'>8</span>
+<span class='line-number'>9</span>
+<span class='line-number'>10</span>
+<span class='line-number'>11</span>
+<span class='line-number'>12</span>
+<span class='line-number'>13</span>
+<span class='line-number'>14</span>
+<span class='line-number'>15</span>
+<span class='line-number'>16</span>
+</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="kn">from</span> <span class="nn">django.contrib.auth.hashers</span> <span class="kn">import</span> <span class="n">BCryptPasswordHasher</span>
+</span><span class='line'><span class="kn">from</span> <span class="nn">django.utils.crypto</span> <span class="kn">import</span> <span class="n">constant_time_compare</span>
+</span><span class='line'><span class="kn">from</span> <span class="nn">django.utils.encoding</span> <span class="kn">import</span> <span class="n">force_bytes</span>
+</span><span class='line'>
+</span><span class='line'>
+</span><span class='line'><span class="k">class</span> <span class="nc">DjangoBCryptPasswordHasher</span><span class="p">(</span><span class="n">BCryptPasswordHasher</span><span class="p">):</span>
+</span><span class='line'> <span class="sd">&quot;&quot;&quot;</span>
+</span><span class='line'><span class="sd"> Handles legacy passwords wich were hashed with the &#39;bc$&#39; algorithm via</span>
+</span><span class='line'><span class="sd"> django-bcrypt.</span>
+</span><span class='line'><span class="sd"> &quot;&quot;&quot;</span>
+</span><span class='line'> <span class="n">algorithm</span> <span class="o">=</span> <span class="s">&quot;bc&quot;</span>
+</span><span class='line'>
+</span><span class='line'> <span class="k">def</span> <span class="nf">verify</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">password</span><span class="p">,</span> <span class="n">encoded</span><span class="p">):</span>
+</span><span class='line'> <span class="n">data</span> <span class="o">=</span> <span class="n">encoded</span><span class="p">[</span><span class="mi">3</span><span class="p">:]</span>
+</span><span class='line'> <span class="n">bcrypt</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_load_library</span><span class="p">()</span>
+</span><span class='line'> <span class="k">return</span> <span class="n">constant_time_compare</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">bcrypt</span><span class="o">.</span><span class="n">hashpw</span><span class="p">(</span><span class="n">force_bytes</span><span class="p">(</span><span class="n">password</span><span class="p">),</span> <span class="n">data</span><span class="p">))</span>
+</span></code></pre></td></tr></table></div></figure>
+
+<p>Once you&#8217;ve defined the backend, the rest is as simple as adding it to your list of password hashers:</p>
+
+<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
+<span class='line-number'>2</span>
+<span class='line-number'>3</span>
+<span class='line-number'>4</span>
+<span class='line-number'>5</span>
+<span class='line-number'>6</span>
+<span class='line-number'>7</span>
+<span class='line-number'>8</span>
+</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">PASSWORD_HASHERS</span> <span class="o">=</span> <span class="p">(</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.PBKDF2PasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.BCryptPasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;getsentry.utils.auth.DjangoBCryptPasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.SHA1PasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;django.contrib.auth.hashers.MD5PasswordHasher&#39;</span><span class="p">,</span>
+</span><span class='line'><span class="p">)</span>
+</span></code></pre></td></tr></table></div></figure>
+]]></content>
+ </entry>
+
+ <entry>
<title type="html"><![CDATA[A Weekend In Russia]]></title>
<link href="http://justcramer.com/2013/02/27/a-weekend-in-russia"/>
<updated>2013-02-27T00:06:00-08:00</updated>
@@ -1758,99 +1829,4 @@ id | timestamp | title
]]></content>
</entry>
- <entry>
- <title type="html"><![CDATA[Error Tracing in Sentry]]></title>
- <link href="http://justcramer.com/2011/01/25/error-tracing-in-sentry"/>
- <updated>2011-01-25T00:00:00-08:00</updated>
- <id>http://justcramer.com/2011/01/25/error-tracing-in-sentry</id>
- <content type="html"><![CDATA[<p>A few weeks ago we pushed out an update to <a href="http://github.com/dcramer/django-sentry">Sentry</a>, bumping it&#8217;s version to 1.6.0. Among the changes was a new &#8220;Sentry ID&#8221; value which is created by the client, rather than relying on the server. This seems like something insignificant, but it allows you to do something very powerful: trace errors from the customer or developer down to the precise request and log entry.</p>
-
-<h4>Exposing Sentry ID</h4>
-
-<p>The new IDs are generated automatically when a message is processed (by the client), so you won&#8217;t need to make any changes on that end. Likely, however, you&#8217;re going to want to expose these at your application level for a couple of different reasons. The first one we&#8217;re going to cover is your customer&#8217;s experience.</p>
-
-<p>The easiest way to expose this information in a useful manner, is by <strong>creating a modified 500.html</strong>. In DISQUS&#8217; case, we mention the error reference ID to the end-user, so that when they&#8217;re reporting a problem they can pass along this information.</p>
-
-<h5>Create a custom 500 handler</h5>
-
-<p>The first thing you&#8217;re going to need to do is to create a custom 500 handler. This defined in <code>urls.py</code>, so we&#8217;re just going to go ahead and create the view in-place.</p>
-
-<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
-<span class='line-number'>2</span>
-<span class='line-number'>3</span>
-<span class='line-number'>4</span>
-<span class='line-number'>5</span>
-<span class='line-number'>6</span>
-<span class='line-number'>7</span>
-<span class='line-number'>8</span>
-<span class='line-number'>9</span>
-<span class='line-number'>10</span>
-<span class='line-number'>11</span>
-<span class='line-number'>12</span>
-<span class='line-number'>13</span>
-<span class='line-number'>14</span>
-<span class='line-number'>15</span>
-<span class='line-number'>16</span>
-<span class='line-number'>17</span>
-<span class='line-number'>18</span>
-<span class='line-number'>19</span>
-</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">def</span> <span class="nf">handler500</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
-</span><span class='line'> <span class="sd">&quot;&quot;&quot;</span>
-</span><span class='line'><span class="sd"> An error handler which exposes the request object to the error template.</span>
-</span><span class='line'><span class="sd"> &quot;&quot;&quot;</span>
-</span><span class='line'> <span class="kn">from</span> <span class="nn">django.template</span> <span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">loader</span>
-</span><span class='line'> <span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseServerError</span>
-</span><span class='line'> <span class="kn">from</span> <span class="nn">disqus.context_processors</span> <span class="kn">import</span> <span class="n">default</span>
-</span><span class='line'> <span class="kn">import</span> <span class="nn">logging</span>
-</span><span class='line'> <span class="kn">import</span> <span class="nn">sys</span>
-</span><span class='line'> <span class="k">try</span><span class="p">:</span>
-</span><span class='line'> <span class="n">context</span> <span class="o">=</span> <span class="n">default</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
-</span><span class='line'> <span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
-</span><span class='line'> <span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exc_info</span><span class="o">=</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">(),</span> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;request&#39;</span><span class="p">:</span> <span class="n">request</span><span class="p">})</span>
-</span><span class='line'> <span class="n">context</span> <span class="o">=</span> <span class="p">{}</span>
-</span><span class='line'>
-</span><span class='line'> <span class="n">context</span><span class="p">[</span><span class="s">&#39;request&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">request</span>
-</span><span class='line'>
-</span><span class='line'> <span class="n">t</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="s">&#39;500.html&#39;</span><span class="p">)</span> <span class="c"># You need to create a 500.html template.</span>
-</span><span class='line'> <span class="k">return</span> <span class="n">HttpResponseServerError</span><span class="p">(</span><span class="n">t</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">Context</span><span class="p">(</span><span class="n">context</span><span class="p">)))</span>
-</span></code></pre></td></tr></table></div></figure>
-
-<p>We&#8217;re going to expose the request object to our 500.html in the above. Keep in mind, that doing this allows you to add some logic into your template, and you&#8217;re going to need to be very careful that this logic can&#8217;t raise a new exception.</p>
-
-<h5>Tweaking your 500.html</h5>
-
-<p>The next thing you&#8217;ll need to do is to tweak your 500.html template to actually show the Sentry ID. Assuming the request object was passed into Sentry, it will attach the last error seen under <code>request.sentry['id']</code>. Given this, we can easily report it to the end-user in our template:</p>
-
-<pre>
-&lt;p&gt;The Disqus team has been alerted and we're on the case. For more information, check out &lt;a href="http://status.disqus.com"&gt;Disqus Status &raquo;&lt;/a&gt;&lt;/p&gt;
-&#123;% if request.sentry.id %&#125;
- &lt;p&gt;If you need assistance, you may reference this error as &lt;strong&gt;&#123;&#123; request.sentry.id &#125;&#125;&lt;/strong&gt;.&lt;/p&gt;
-&#123;% endif %&#125;
-</pre>
-
-<h4>Sentry ID as a response header</h4>
-
-<p>The other quick solution to get access to this variable is simply by enabling an included response middleware, <code>SentryResponseErrorIdMiddleware</code>. Just pop open your <code>settings.py</code> and append it to your <code>MIDDLEWARE_CLASSES</code>:</p>
-
-<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
-<span class='line-number'>2</span>
-<span class='line-number'>3</span>
-<span class='line-number'>4</span>
-</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">MIDDLEWARE_CLASSES</span> <span class="o">=</span> <span class="p">(</span>
-</span><span class='line'> <span class="o">...</span><span class="p">,</span>
-</span><span class='line'> <span class="s">&#39;sentry.client.middleware.SentryResponseErrorIdMiddleware&#39;</span><span class="p">,</span>
-</span><span class='line'><span class="p">)</span>
-</span></code></pre></td></tr></table></div></figure>
-
-<p>Now if you check your response headers after hitting an error, you should see <code>X-Sentry-ID</code>.</p>
-
-<h4>Find errors by ID</h4>
-
-<p>Sentry makes it very easy to pull up error messages by ID. The one requirement is that you&#8217;re going to need to ensure <code>sentry.filters.SearchFilter</code> is included within <code>SENTRY_FILTERS</code> (it&#8217;s enabled by default). Once done, Sentry will discover if you&#8217;re entering a UUID hex value (the Sentry ID) in the search box, and it will jump directly to that error&#8217;s page.</p>
-
-<p><img src="http://f.cl.ly/items/2f1s1X0J231F2F3u0V0d/sentry-id.png"/></p>
-
-<p>You&#8217;ll also notice that all messages are now tagged with their unique Sentry ID as well (per the screenshot).</p>]]></content>
- </entry>
-
</feed>
View
26 blog/archives/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="2013 A Weekend In Russia Feb 27 django, python Comments Moving On Feb 11 Comments Dependency Graphs and Package Versioning Jan 29 python Comments &hellip;">
+ <meta name="description" content="2013 Making Django 1.5 compatible with django-bcrypt May 7 django Comments A Weekend In Russia Feb 27 django, python Comments Moving On Feb 11 &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -76,6 +76,30 @@ <h1 class="archive-title">2013</h1>
<article class="archive">
+<h1 class="title"><a href="/2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt">Making Django 1.5 compatible with django-bcrypt</a></h1>
+<div class="meta">
+ <span class="date">May 7</span>
+ <span class="tags">
+
+<div class="cat">
+
+ <a class='category' href='/categories/django/'>django</a>
+
+</div>
+
+</span>
+
+ <span class="comments"><a href="/2013/05/07/making-django-1-dot-5-compatible-with-django-bcrypt#disqus_thread">Comments</a></span>
+
+</div>
+ </article>
+</section>
+
+<section class="archive">
+
+
+ <article class="archive">
+
<h1 class="title"><a href="/2013/02/27/a-weekend-in-russia">A Weekend In Russia</a></h1>
<div class="meta">
<span class="date">Feb 27</span>
View
62 blog/page/10/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="PHP vs Python &#8211; Where Opinions Aren&#8217;t Wanted Constantly, and only in Python channels, I hear the argument brought up that &#8220;PHP is &hellip;">
+ <meta name="description" content="iBegin Share 2.3 &#8211; Now With Stats! We have pushed out iBegin Share 2.3 (and wp plugin 1.2 to go along with it). It&#8217;s a pretty mild &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,37 @@
<article class="post">
+ <h1 class="title"><a href="/2008/04/16/ibegin-share-23-now-with-stats">iBegin Share 2.3 &#8211; Now With Stats!</a></h1>
+ <div class="entry">
+ <p>We have pushed out <a href="http://www.ibegin.com/labs/share/">iBegin Share 2.3</a> (and wp plugin 1.2 to go along with it). It&#8217;s a pretty mild update, that includes one pretty cool new feature: Statistics. We&#8217;ve built in some quick stats to let you see how people are using the share plugin, on your blog, or standalone (although the WP integration is pretty wicked).</p>
+
+<p>We have also updated the button to use the open share icon.</p>
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2008-04-16T00:00:00-07:00" pubdate data-updated="true">Apr 16<span>th</span>, 2008</time></div>
+ <div class="tags">
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2008/04/14/php-vs-python">PHP vs Python &#8211; Where Opinions Aren&#8217;t Wanted</a></h1>
<div class="entry">
<p>Constantly, and only in Python channels, I hear the argument brought up that &#8220;PHP is &lt;insert random insult&gt;&#8221; or &#8220;&lt;N&gt; is a PHP developer so he must suck&#8221;. One of the things I hate most, is stereotypes, based on false information. Stereotypes about people from Texas being rednecks are ok, because it&#8217;s true. Now, let&#8217;s get into this a bit more.</p>
@@ -510,35 +541,6 @@ <h1 class="title"><a href="/2008/03/29/using-jinja-with-django">Using Jinja With
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2008/03/27/making-django-newforms-useful">Making Django Newforms Useful</a></h1>
- <div class="entry">
- <p>One of my goals, beyond the constant improvement of the ORM in Django, is to make django.newforms easier for all of the lazy people, like myself, which I know are plentiful. I personally hate the repetitive task of creating templates for your forms, and the as_X methods are extremely limited. So let&#8217;s get down to business.<br>
-
- <a href="/2008/03/27/making-django-newforms-useful" class="more-link">Read on &rarr;</a>
- </div>
- <div class="meta">
- <div class="date">
-
-
-
-
-
-
-
-
-
-
-
-<time datetime="2008-03-27T00:00:00-07:00" pubdate data-updated="true">Mar 27<span>th</span>, 2008</time></div>
- <div class="tags">
-
-</div>
-
- </div>
-</article>
-
<nav id="pagenavi">
<a href="/blog/page/9/" class="prev">Prev</a>
View
72 blog/page/11/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="ModelChoiceFields as CharFields in Django Today I was creating the submission form for the new iBegin.com homepage. In this we use a lot of &hellip;">
+ <meta name="description" content="Making Django Newforms Useful One of my goals, beyond the constant improvement of the ORM in Django, is to make django.newforms easier for all of &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,35 @@
<article class="post">
+ <h1 class="title"><a href="/2008/03/27/making-django-newforms-useful">Making Django Newforms Useful</a></h1>
+ <div class="entry">
+ <p>One of my goals, beyond the constant improvement of the ORM in Django, is to make django.newforms easier for all of the lazy people, like myself, which I know are plentiful. I personally hate the repetitive task of creating templates for your forms, and the as_X methods are extremely limited. So let&#8217;s get down to business.<br>
+
+ <a href="/2008/03/27/making-django-newforms-useful" class="more-link">Read on &rarr;</a>
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2008-03-27T00:00:00-07:00" pubdate data-updated="true">Mar 27<span>th</span>, 2008</time></div>
+ <div class="tags">
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2008/03/24/modelchoicefields-as-charfields-in-django">ModelChoiceFields as CharFields in Django</a></h1>
<div class="entry">
<p>Today I was creating the submission form for the new iBegin.com homepage. In this we use a lot of JavaScript to make the process more clean. One such use, was an autocomplete on Cities and Categories. To do this, and to keep validation, you need to use a ModelChoiceField, but using a ModelChoiceField with a TextInput doesn&#8217;t work. So, I give you an <a href="http://www.pastethat.com/django-inlinemodelchoice">InlineModelChoiceField in Django</a>.</p>
@@ -366,47 +395,6 @@ <h1 class="title"><a href="/2008/03/13/pastethats-super-sexy-revamp">PasteThat&#
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2008/03/12/word-wrap-preformatted-text">Word-wrap Preformatted Text</a></h1>
- <div class="entry">
- <p>I was searching the internet the other day for a solution to word-wrap preformatted text for <a href="http://www.pastethat.com">pastethat.com</a>. Low and behold, Google answers all, it just takes finding the right keywords. So, the solution:</p>
-<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
-<span class='line-number'>2</span>
-<span class='line-number'>3</span>
-<span class='line-number'>4</span>
-<span class='line-number'>5</span>
-</pre></td><td class='code'><pre><code class='css'><span class='line'><span class="nt">white-space</span><span class="o">:</span> <span class="nt">pre-wrap</span><span class="o">;</span> <span class="c">/* CSS-3 */</span>
-</span><span class='line'><span class="nt">white-space</span><span class="o">:</span> <span class="nt">-moz-pre-wrap</span><span class="o">;</span> <span class="c">/* Mozilla, since 1999 */</span>
-</span><span class='line'><span class="nt">white-space</span><span class="o">:</span> <span class="nt">-pre-wrap</span><span class="o">;</span> <span class="c">/* Opera 4-6 */</span>
-</span><span class='line'><span class="nt">white-space</span><span class="o">:</span> <span class="nt">-o-pre-wrap</span><span class="o">;</span> <span class="c">/* Opera 7 */</span>
-</span><span class='line'><span class="nt">word-wrap</span><span class="o">:</span> <span class="nt">break-word</span><span class="o">;</span> <span class="c">/* Internet Explorer 5.5+ */</span>
-</span></code></pre></td></tr></table></div></figure>
-
-
-
- </div>
- <div class="meta">
- <div class="date">
-
-
-
-
-
-
-
-
-
-
-
-<time datetime="2008-03-12T00:00:00-07:00" pubdate data-updated="true">Mar 12<span>th</span>, 2008</time></div>
- <div class="tags">
-
-</div>
-
- </div>
-</article>
-
<nav id="pagenavi">
<a href="/blog/page/10/" class="prev">Prev</a>
View
110 blog/page/12/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="A Better Lightbox - iBox V2 One of my first projects at the new company has been updating a script called iBox. Most people are familiar with the &hellip;">
+ <meta name="description" content="Word-wrap Preformatted Text I was searching the internet the other day for a solution to word-wrap preformatted text for pastethat.com. Low and &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,47 @@
<article class="post">
+ <h1 class="title"><a href="/2008/03/12/word-wrap-preformatted-text">Word-wrap Preformatted Text</a></h1>
+ <div class="entry">
+ <p>I was searching the internet the other day for a solution to word-wrap preformatted text for <a href="http://www.pastethat.com">pastethat.com</a>. Low and behold, Google answers all, it just takes finding the right keywords. So, the solution:</p>
+<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
+<span class='line-number'>2</span>
+<span class='line-number'>3</span>
+<span class='line-number'>4</span>
+<span class='line-number'>5</span>
+</pre></td><td class='code'><pre><code class='css'><span class='line'><span class="nt">white-space</span><span class="o">:</span> <span class="nt">pre-wrap</span><span class="o">;</span> <span class="c">/* CSS-3 */</span>
+</span><span class='line'><span class="nt">white-space</span><span class="o">:</span> <span class="nt">-moz-pre-wrap</span><span class="o">;</span> <span class="c">/* Mozilla, since 1999 */</span>
+</span><span class='line'><span class="nt">white-space</span><span class="o">:</span> <span class="nt">-pre-wrap</span><span class="o">;</span> <span class="c">/* Opera 4-6 */</span>
+</span><span class='line'><span class="nt">white-space</span><span class="o">:</span> <span class="nt">-o-pre-wrap</span><span class="o">;</span> <span class="c">/* Opera 7 */</span>
+</span><span class='line'><span class="nt">word-wrap</span><span class="o">:</span> <span class="nt">break-word</span><span class="o">;</span> <span class="c">/* Internet Explorer 5.5+ */</span>
+</span></code></pre></td></tr></table></div></figure>
+
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2008-03-12T00:00:00-07:00" pubdate data-updated="true">Mar 12<span>th</span>, 2008</time></div>
+ <div class="tags">
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2008/03/11/ibox-v2-released">A Better Lightbox - iBox V2</a></h1>
<div class="entry">
<p>One of my first projects at the new company has been updating a script called iBox. Most people are familiar with the concept, that of lightbox, as well as how inefficient most of the scripts are. The goal of iBox is simple: provide a lightweight modal dialog box with additional support for document types to act as an <a href="http://gamma.ibegin.com/ibox/">efficient alternative to lightbox</a>. iBox v2 does just that!<br>
@@ -356,73 +397,6 @@ <h1 class="title"><a href="/2008/01/21/unicode-update-for-django-sphinx">Unicode
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2008/01/21/caching-layer-for-django-orm">Caching Layer for Django ORM</a></h1>
- <div class="entry">
- <p>I&#8217;ve finally completed what I&#8217;ll call &#8220;phase 1&#8221; of the caching layer. It handles the easiest, and for my cases, the most useful level of cache invalidation: removing objects.</p>
-
-<p><strong>&#8220;Phase 1&#8221; Features:</strong><br><ul><li>Automatic caching of querysets.</li><li>Invalidating querysets when an object is removed.</li><li>Caching querysets objects in a key by key basis (per-object caching).</li><li>Automatic invalidation of per-object caches.</li></ul></p>
-
-<p><a href="http://code.google.com/p/django-orm-cache/">Grab the code from Google</a> and look it over if you&#8217;re interested. This is still very much in a &#8220;It probably doesn&#8217;t work correctly&#8221; phase, and the code will have a lot of cleanup and structure changes before it&#8217;s done.</p>
-
-<p>Here&#8217;s a quick rundown of the intended functionality and SQL usage:</p>
-
-<pre>
-class MyModel(CachedModel): [...]
-
-MyModel.objects.create(name="Test") [1 query]
-
-MyModel.objects.all() [1 query ]
-[Test,]
-
-MyModel.objects.create(name="Test2") [1 query]
-
-MyModel.objects.all() [no queries]
-[Test,]
-
-MyModel.objects.create(name="Test3") [1 query]
-
-MyModel.objects.all().reset() [1 query]
->>> [Test, Test2, Test3]
-
-MyModel.objects.get(name="Test2").delete() [1 query]
-
-MyModel.objects.all() [2 queries]
-[Test, Test3]
-
-z = MyModel.objects.get(name="Test")
-z.name = "Test Changed"
-z.save() [1 query]
-
-MyModel.objects.all() [no queries]
-[Test Changed, Test3]
-</pre>
-
-
-
- </div>
- <div class="meta">
- <div class="date">
-
-
-
-
-
-
-
-
-
-
-
-<time datetime="2008-01-21T00:00:00-08:00" pubdate data-updated="true">Jan 21<span>st</span>, 2008</time></div>
- <div class="tags">
-
-</div>
-
- </div>
-</article>
-
<nav id="pagenavi">
<a href="/blog/page/11/" class="prev">Prev</a>
View
102 blog/page/13/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="Firefox Extension Version Changer (Because I didn&#8217;t know what else to call it). Anyways, I updated to Firefox 3 when RC1 came out. I figure &hellip;">
+ <meta name="description" content="Caching Layer for Django ORM I&#8217;ve finally completed what I&#8217;ll call &#8220;phase 1&#8221; of the caching layer. It handles the easiest, &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,73 @@
<article class="post">
+ <h1 class="title"><a href="/2008/01/21/caching-layer-for-django-orm">Caching Layer for Django ORM</a></h1>
+ <div class="entry">
+ <p>I&#8217;ve finally completed what I&#8217;ll call &#8220;phase 1&#8221; of the caching layer. It handles the easiest, and for my cases, the most useful level of cache invalidation: removing objects.</p>
+
+<p><strong>&#8220;Phase 1&#8221; Features:</strong><br><ul><li>Automatic caching of querysets.</li><li>Invalidating querysets when an object is removed.</li><li>Caching querysets objects in a key by key basis (per-object caching).</li><li>Automatic invalidation of per-object caches.</li></ul></p>
+
+<p><a href="http://code.google.com/p/django-orm-cache/">Grab the code from Google</a> and look it over if you&#8217;re interested. This is still very much in a &#8220;It probably doesn&#8217;t work correctly&#8221; phase, and the code will have a lot of cleanup and structure changes before it&#8217;s done.</p>
+
+<p>Here&#8217;s a quick rundown of the intended functionality and SQL usage:</p>
+
+<pre>
+class MyModel(CachedModel): [...]
+
+MyModel.objects.create(name="Test") [1 query]
+
+MyModel.objects.all() [1 query ]
+[Test,]
+
+MyModel.objects.create(name="Test2") [1 query]
+
+MyModel.objects.all() [no queries]
+[Test,]
+
+MyModel.objects.create(name="Test3") [1 query]
+
+MyModel.objects.all().reset() [1 query]
+>>> [Test, Test2, Test3]
+
+MyModel.objects.get(name="Test2").delete() [1 query]
+
+MyModel.objects.all() [2 queries]
+[Test, Test3]
+
+z = MyModel.objects.get(name="Test")
+z.name = "Test Changed"
+z.save() [1 query]
+
+MyModel.objects.all() [no queries]
+[Test Changed, Test3]
+</pre>
+
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2008-01-21T00:00:00-08:00" pubdate data-updated="true">Jan 21<span>st</span>, 2008</time></div>
+ <div class="tags">
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2008/01/19/firefox-extension-version-changer">Firefox Extension Version Changer</a></h1>
<div class="entry">
<p>(Because I didn&#8217;t know what else to call it).</p>
@@ -576,39 +643,6 @@ <h1 class="title"><a href="/2007/11/28/curse-version-5">Curse &#8211; Version 5<
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2007/11/14/dpaste-was-down">Dpaste Was Down</a></h1>
- <div class="entry">
- <p>So today, being the usual day, I needed a pastebin, that wasn&#8217;t <a href="http://www.pastebin.com">slow</a>, or <a href="http://www.pastebin.ca">bogged up</a> with ads and stuff. I hopped on over to <a href="http://www.dpaste.com/">dpaste.com</a> as I usually would, to find that the domain was temporarily expired (it&#8217;s back up now). Being that the site was down for a little bit, and the project was small, I took an hour to write a pastebin (in PHP, I know).</p>
-
-<p>So, here you have it, with enough features to hold you over, and robust enough to be slashdotted: <a href="http://www.pastethat.com/">PasteThat.</a></p>
-
-<p>The featureset:<br><ul><br><li>Pastes are generated with a unique key &#8211; I myself don&#8217;t want random people reading my pastes :)</li><br><li>Pastes never expire &#8211; there&#8217;s really no storage limitation on my system</li><br><li>It uses the Geshi syntax highlighter &#8211; which seems slow, so I&#8217;ll have to optimize it if people actually use the site</li><br><li>It will remember your name and syntax if you let it set a cookie.</li><br><li>It automatically adjusts the size of the textarea based on your browser window&#8217;s size.</li><br><li>You can post follow ups (and with comments as soon as I get home), as well as view followups for a post.</li><br></ul><br>TODO (when I feel like it and am not busy with work)<br><ul><br><li>Add tags to each paste</li><br><li>Add a public boolean for each paste</li><br><li>Allow people to browse public pastes by tags/date/traffic</li><br></ul><br>The simple goal: A robust and simplified pastebin that has many uses.. and I won&#8217;t ever have to worry about not being able to use.</p>
-
-
- </div>
- <div class="meta">
- <div class="date">
-
-
-
-
-
-
-
-
-
-
-
-<time datetime="2007-11-14T00:00:00-08:00" pubdate data-updated="true">Nov 14<span>th</span>, 2007</time></div>
- <div class="tags">
-
-</div>
-
- </div>
-</article>
-
<nav id="pagenavi">
<a href="/blog/page/12/" class="prev">Prev</a>
View
68 blog/page/14/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="MySQLdb on Leopard As many people probably have, I ran across the problem of installing MySQLdb (Python) on Leopard today. The error: In file &hellip;">
+ <meta name="description" content="Dpaste Was Down So today, being the usual day, I needed a pastebin, that wasn&#8217;t slow, or bogged up with ads and stuff. I hopped on over to &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,39 @@
<article class="post">
+ <h1 class="title"><a href="/2007/11/14/dpaste-was-down">Dpaste Was Down</a></h1>
+ <div class="entry">
+ <p>So today, being the usual day, I needed a pastebin, that wasn&#8217;t <a href="http://www.pastebin.com">slow</a>, or <a href="http://www.pastebin.ca">bogged up</a> with ads and stuff. I hopped on over to <a href="http://www.dpaste.com/">dpaste.com</a> as I usually would, to find that the domain was temporarily expired (it&#8217;s back up now). Being that the site was down for a little bit, and the project was small, I took an hour to write a pastebin (in PHP, I know).</p>
+
+<p>So, here you have it, with enough features to hold you over, and robust enough to be slashdotted: <a href="http://www.pastethat.com/">PasteThat.</a></p>
+
+<p>The featureset:<br><ul><br><li>Pastes are generated with a unique key &#8211; I myself don&#8217;t want random people reading my pastes :)</li><br><li>Pastes never expire &#8211; there&#8217;s really no storage limitation on my system</li><br><li>It uses the Geshi syntax highlighter &#8211; which seems slow, so I&#8217;ll have to optimize it if people actually use the site</li><br><li>It will remember your name and syntax if you let it set a cookie.</li><br><li>It automatically adjusts the size of the textarea based on your browser window&#8217;s size.</li><br><li>You can post follow ups (and with comments as soon as I get home), as well as view followups for a post.</li><br></ul><br>TODO (when I feel like it and am not busy with work)<br><ul><br><li>Add tags to each paste</li><br><li>Add a public boolean for each paste</li><br><li>Allow people to browse public pastes by tags/date/traffic</li><br></ul><br>The simple goal: A robust and simplified pastebin that has many uses.. and I won&#8217;t ever have to worry about not being able to use.</p>
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2007-11-14T00:00:00-08:00" pubdate data-updated="true">Nov 14<span>th</span>, 2007</time></div>
+ <div class="tags">
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2007/11/05/mysqldb-on-leopard">MySQLdb on Leopard</a></h1>
<div class="entry">
<p>As many people probably have, I ran across the problem of installing MySQLdb (Python) on Leopard today.</p>
@@ -396,39 +429,6 @@ <h1 class="title"><a href="/2007/06/22/wowheadcom-joins-the-ige-parade">Wowhead.
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2007/06/11/safari-now-on-windows">Safari; Now on Windows</a></h1>
- <div class="entry">
- <p>All the Mac fans can rejoice. The ever so popular browser seems to have finally made it to Windows to tag alongside Quicktime and iTunes.</p>
-
-<p>I&#8217;ve yet to try out the latest verison, but it seems promising. It delivers with several new features, and claims to be the fastest browser available, even on Windows.</p>
-
-<p>For more information, and to download Safari, head over to <a href="http://www.apple.com/safari/download/">Apple</a>.</p>
-
-
- </div>
- <div class="meta">
- <div class="date">
-
-
-
-
-
-
-
-
-
-
-
-<time datetime="2007-06-11T00:00:00-07:00" pubdate data-updated="true">Jun 11<span>th</span>, 2007</time></div>
- <div class="tags">
-
-</div>
-
- </div>
-</article>
-
<nav id="pagenavi">
<a href="/blog/page/13/" class="prev">Prev</a>
View
78 blog/page/15/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="It Begins &#8211; Curse.com So we put up the splash page today and began giving some people beta access. So far everyone loves what we&#8217;re &hellip;">
+ <meta name="description" content="Safari; Now on Windows All the Mac fans can rejoice. The ever so popular browser seems to have finally made it to Windows to tag alongside Quicktime &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,39 @@
<article class="post">
+ <h1 class="title"><a href="/2007/06/11/safari-now-on-windows">Safari; Now on Windows</a></h1>
+ <div class="entry">
+ <p>All the Mac fans can rejoice. The ever so popular browser seems to have finally made it to Windows to tag alongside Quicktime and iTunes.</p>
+
+<p>I&#8217;ve yet to try out the latest verison, but it seems promising. It delivers with several new features, and claims to be the fastest browser available, even on Windows.</p>
+
+<p>For more information, and to download Safari, head over to <a href="http://www.apple.com/safari/download/">Apple</a>.</p>
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2007-06-11T00:00:00-07:00" pubdate data-updated="true">Jun 11<span>th</span>, 2007</time></div>
+ <div class="tags">
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2007/06/07/it-begins-cursecom">It Begins &#8211; Curse.com</a></h1>
<div class="entry">
<p>So we put up the splash page today and began giving some people beta access. So far everyone loves what we&#8217;re doing with the new site, and I think it&#8217;s going to go really well at release.</p>
@@ -340,49 +373,6 @@ <h1 class="title"><a href="/2006/10/23/curse-gaming-beta-tests-new-website">Curs
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2006/10/22/tracking-unread-objects">Tracking Unread Objects</a></h1>
- <div class="entry">
- <p>Recently I&#8217;ve had to develop forum software for a website, and one problem we ran into was the most robust way to track unread posts.</p>
-
-<p>After giving this some thought, I came up with two feasable options. We&#8217;ll start by taking a look at the first.</p>
-
-<p><strong>Pure Post Tracking</strong></p>
-
-<p>Method one is to create a table:<br><blockquote>&#8220;forum_views&#8221;<br>postID (IntegerField)<br>userID (IntegerField)<br>Index (postID, userID)</blockquote><br>Everytime a user would view a post (that was marked as unread) we would insert a row into the table. To output the list of posts, or threads, we would be join the thread with this table.</p>
-
-<p>Cons:<br><ul><br><li>In order to show the list of threads, or forums, you have to use a LEFT JOIN with the Thread and Views table (even on the forum index) which can be extremely slow on high load websites.</li><br><li>A different queryset is used for each user, so there&#8217;s no worthwhile caching for this method.</li><br><li>Upon viewing a thread you have to perform a query for each post that is marked as unread.</li><br></ul><br>Pros:<br><ul><br><li>It gives exact tracking on if a user has viewed a post.</li><br></ul><br>Obviously, the pros do NOT outweigh the cons, so let&#8217;s move on to the other method:</p>
-
-<p><strong>Session Time Tracking</strong></p>
-
-<p>The idea of this is simple, and extremely quick. Our first step is to modify our User table if it&#8217;s not already setup properly. We need to add one field:<br><blockquote>&#8220;users&#8221;<br>lastVisitTime (DateTimeField)</blockquote><br>Ok now we have a field in our users table, which tracks the last time they visited the website. Now, obviously, the first obstacle is keeping the last visit time, as the time they last visisted the site, and not the last time they viewed a page. The way we will do this is quite simple:<br><ol><br><li>First and foremost, we validate their login details, if they&#8217;re not anonymous.</li><br><li>Next we check for a session variable, let&#8217;s call it &#8220;user_lastvisit&#8221;.</li><br><li>If this variable does not exist, we will set it to the data in our table for lastVisitTime, or -1 (if they&#8217;re anonymous, or have no lastVisitTime)</li><br><li>If they are not anonymous, we now need to update our User table lastVisitTime with the current time.</li><br></ol><br>Now, as you can see, we have the session variable, user_lastvisit, and we can use this in our template, or view, in a loop over all of the <strong>cached</strong> query results, to see if the last reply time is greater than the last visit time.</p>
-
-<p>Cons:<br><ul><br><li>It&#8217;s generic tracking; the minute the session is destroyed it marks all threads as read.</li><br><li>It does not track on a per-thread basis, although it could be combined with example #1 to do so.</li><br></ul><br>Pros:<br><ul><br><li>Extremely robust and quick, works well with caching solutions.</li><br><li>No large database overhead for tracking views.</li><br><li>No added database load for marking threads as read.</li><br></ul><br>If you want accurate tracking, I would recommend tracking views as said in example #1, with the views table, and then using example #2 for tracking on lists. The accurate tracking is most notably usable in search results.</p>
-
-
- </div>
- <div class="meta">
- <div class="date">
-
-
-
-
-
-
-
-
-
-
-
-<time datetime="2006-10-22T00:00:00-07:00" pubdate data-updated="true">Oct 22<span>nd</span>, 2006</time></div>
- <div class="tags">
-
-</div>
-
- </div>
-</article>
-
<nav id="pagenavi">
<a href="/blog/page/14/" class="prev">Prev</a>
View
84 blog/page/16/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="Avast, Me Hearties! Today be International Talk like a Sea dog Tide. Sea dogs an&#8217; land lubbers&#8217;s encouraged t&#8217; spice up the&#8217; &hellip;">
+ <meta name="description" content="Tracking Unread Objects Recently I&#8217;ve had to develop forum software for a website, and one problem we ran into was the most robust way to &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,49 @@
<article class="post">
+ <h1 class="title"><a href="/2006/10/22/tracking-unread-objects">Tracking Unread Objects</a></h1>
+ <div class="entry">
+ <p>Recently I&#8217;ve had to develop forum software for a website, and one problem we ran into was the most robust way to track unread posts.</p>
+
+<p>After giving this some thought, I came up with two feasable options. We&#8217;ll start by taking a look at the first.</p>
+
+<p><strong>Pure Post Tracking</strong></p>
+
+<p>Method one is to create a table:<br><blockquote>&#8220;forum_views&#8221;<br>postID (IntegerField)<br>userID (IntegerField)<br>Index (postID, userID)</blockquote><br>Everytime a user would view a post (that was marked as unread) we would insert a row into the table. To output the list of posts, or threads, we would be join the thread with this table.</p>
+
+<p>Cons:<br><ul><br><li>In order to show the list of threads, or forums, you have to use a LEFT JOIN with the Thread and Views table (even on the forum index) which can be extremely slow on high load websites.</li><br><li>A different queryset is used for each user, so there&#8217;s no worthwhile caching for this method.</li><br><li>Upon viewing a thread you have to perform a query for each post that is marked as unread.</li><br></ul><br>Pros:<br><ul><br><li>It gives exact tracking on if a user has viewed a post.</li><br></ul><br>Obviously, the pros do NOT outweigh the cons, so let&#8217;s move on to the other method:</p>
+
+<p><strong>Session Time Tracking</strong></p>
+
+<p>The idea of this is simple, and extremely quick. Our first step is to modify our User table if it&#8217;s not already setup properly. We need to add one field:<br><blockquote>&#8220;users&#8221;<br>lastVisitTime (DateTimeField)</blockquote><br>Ok now we have a field in our users table, which tracks the last time they visited the website. Now, obviously, the first obstacle is keeping the last visit time, as the time they last visisted the site, and not the last time they viewed a page. The way we will do this is quite simple:<br><ol><br><li>First and foremost, we validate their login details, if they&#8217;re not anonymous.</li><br><li>Next we check for a session variable, let&#8217;s call it &#8220;user_lastvisit&#8221;.</li><br><li>If this variable does not exist, we will set it to the data in our table for lastVisitTime, or -1 (if they&#8217;re anonymous, or have no lastVisitTime)</li><br><li>If they are not anonymous, we now need to update our User table lastVisitTime with the current time.</li><br></ol><br>Now, as you can see, we have the session variable, user_lastvisit, and we can use this in our template, or view, in a loop over all of the <strong>cached</strong> query results, to see if the last reply time is greater than the last visit time.</p>
+
+<p>Cons:<br><ul><br><li>It&#8217;s generic tracking; the minute the session is destroyed it marks all threads as read.</li><br><li>It does not track on a per-thread basis, although it could be combined with example #1 to do so.</li><br></ul><br>Pros:<br><ul><br><li>Extremely robust and quick, works well with caching solutions.</li><br><li>No large database overhead for tracking views.</li><br><li>No added database load for marking threads as read.</li><br></ul><br>If you want accurate tracking, I would recommend tracking views as said in example #1, with the views table, and then using example #2 for tracking on lists. The accurate tracking is most notably usable in search results.</p>
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2006-10-22T00:00:00-07:00" pubdate data-updated="true">Oct 22<span>nd</span>, 2006</time></div>
+ <div class="tags">
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2006/09/19/avast-me-hearties">Avast, Me Hearties!</a></h1>
<div class="entry">
<p>Today be International Talk like a Sea dog Tide. Sea dogs an&#8217; land lubbers&#8217;s encouraged t&#8217; spice up the&#8217;r vocabulary today wi&#8217; a wee trusty gentleman o&#8217; fortune phrases an&#8217; kick aft on th&#8217; beach wi&#8217; a keg o&#8217; rum.</p>
@@ -360,45 +403,6 @@ <h1 class="title"><a href="/2006/06/29/wdb-to-csv-converter">WDB to CSV Converte
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2006/06/13/ill-be-seeing-you-at-blizzcon-06-my-precious-diablo-3">I Spy Diablo 3</a></h1>
- <div class="entry">
- <p>So about a year ago, I posted an article about information (supported with evidence I had) saying Diablo 3 was in development, as a Massively Multiplayer Online Game, based upon the idea of Hell invading Heaven. I also told you it would be, originally, debuted at Blizzcon last year, and I was wrong. Supported by more evidence that it was in development, I concluded that it would have to be shown at E3 &#8216;06. Once again, I was wrong.</p>
-
-<p>So why do I think it&#8217;s going to air at Blizzcon 2006? Well, to be quite honest, Blizzard could slap me in the face again and I could be wrong. Just recently opened up in a Wall Street discussion saying they had developed a formula for doing an MMOG in just 3 years. Not only did they divulge some financial information to go along with this, but they also said all Blizzard &#8220;All Blizzard franchises will become MMOGs.&#8221;. Who doubted me? Obviously not IGN, or any of the other major media sites who announced the upcoming release of Diablo 3 based off of my information and findings.</p>
-
-<p>So why Blizzcon &#8216;06, why not E3 next year? Well, the original idea was that Burning Crusade would be out before Blizzcon &#8216;06, so it wouldn&#8217;t make much sense to have another session covering the game, and what else are they going to cover? Sure, they could have Starcraft Ghost Release Candidate 18 for the PS3 or some other bullshit, but let&#8217;s get serious. So let&#8217;s look at some facts:</p>
-
-<p>* Blizzard North closed in 2005, which was the primary location for the Diablo franchise development. The company was merged with as we know now Blizzard Entertainment.<br>* Supposedly&#8211;“I am musician in Czech Republic. I play not with one orchestra but with many depending on work. I have recently been to Bratislava in Slovak Republic for recording sessions with local Radio Symphony Orchestra, where we just recorded music for Diablo 3.&#8221; Is this legit? You decide.<br>* Heaven vs Hell. Hell invading Heaven. Normal people don&#8217;t come up with this, and if they did, they would work for a company&#8211;perhaps Blizzard Entertainment? Not only is this a very realistic environment for the Diablo franchise, but the information came from a former Blizzard employee, who was in fact working with the Diablo teams at one point.<br>* And of course, the latest information, from Blizzard saying that all franchises will become MMOGs. Granted, this doesn&#8217;t mean it would happen soon, but with all the evidence supporting Diablo 3, and DMCA&#8217;s I consistently receive for releasing crap, I can see this happening.</p>
-
-<p>There is one thing I did want to address as well. As far as I recall, Blizzard said, upon attending Blizzcon, you would receive a Beta code. If I remember correctly, they also stated the Beta code would not be for the World of Warcraft expansion, but a yet unannounced game release. Two days ago, a Blizzard representative said otherwise, &#8220;..that card is your entrance to play World Of Warcraft expansion before most any one else. I would recommend following the instructions and registering.&#8221; I call bullshit, riot anyone?</p>
-
-<p>Now there is one final determining factor. Will there be a Blizzcon &#8216;06? This of course would play a huge rule on if it&#8217;s announced at the event. If there isn&#8217;t, which is up for debate (and I&#8217;m working on getting confirmation right now), then we may not see it until their next event, as there are no other huge announcements upcoming that I&#8217;m aware of. In my opinion they will save this for their own event, as it makes them a lot more do re me than announcing at E3 would.</p>
-
-
- </div>
- <div class="meta">
- <div class="date">
-
-
-
-
-
-
-
-
-
-
-
-<time datetime="2006-06-13T00:00:00-07:00" pubdate data-updated="true">Jun 13<span>th</span>, 2006</time></div>
- <div class="tags">
-
-</div>
-
- </div>
-</article>
-
<nav id="pagenavi">
<a href="/blog/page/15/" class="prev">Prev</a>
View
41 blog/page/17/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="Some New Sites, a New Theory, and the Tourist! So I took a little time and moved my wiki off of World of Warcraft Guru since I won&#8217;t be &hellip;">
+ <meta name="description" content="I Spy Diablo 3 So about a year ago, I posted an article about information (supported with evidence I had) saying Diablo 3 was in development, as a &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,45 @@
<article class="post">
+ <h1 class="title"><a href="/2006/06/13/ill-be-seeing-you-at-blizzcon-06-my-precious-diablo-3">I Spy Diablo 3</a></h1>
+ <div class="entry">
+ <p>So about a year ago, I posted an article about information (supported with evidence I had) saying Diablo 3 was in development, as a Massively Multiplayer Online Game, based upon the idea of Hell invading Heaven. I also told you it would be, originally, debuted at Blizzcon last year, and I was wrong. Supported by more evidence that it was in development, I concluded that it would have to be shown at E3 &#8216;06. Once again, I was wrong.</p>
+
+<p>So why do I think it&#8217;s going to air at Blizzcon 2006? Well, to be quite honest, Blizzard could slap me in the face again and I could be wrong. Just recently opened up in a Wall Street discussion saying they had developed a formula for doing an MMOG in just 3 years. Not only did they divulge some financial information to go along with this, but they also said all Blizzard &#8220;All Blizzard franchises will become MMOGs.&#8221;. Who doubted me? Obviously not IGN, or any of the other major media sites who announced the upcoming release of Diablo 3 based off of my information and findings.</p>
+
+<p>So why Blizzcon &#8216;06, why not E3 next year? Well, the original idea was that Burning Crusade would be out before Blizzcon &#8216;06, so it wouldn&#8217;t make much sense to have another session covering the game, and what else are they going to cover? Sure, they could have Starcraft Ghost Release Candidate 18 for the PS3 or some other bullshit, but let&#8217;s get serious. So let&#8217;s look at some facts:</p>
+
+<p>* Blizzard North closed in 2005, which was the primary location for the Diablo franchise development. The company was merged with as we know now Blizzard Entertainment.<br>* Supposedly&#8211;“I am musician in Czech Republic. I play not with one orchestra but with many depending on work. I have recently been to Bratislava in Slovak Republic for recording sessions with local Radio Symphony Orchestra, where we just recorded music for Diablo 3.&#8221; Is this legit? You decide.<br>* Heaven vs Hell. Hell invading Heaven. Normal people don&#8217;t come up with this, and if they did, they would work for a company&#8211;perhaps Blizzard Entertainment? Not only is this a very realistic environment for the Diablo franchise, but the information came from a former Blizzard employee, who was in fact working with the Diablo teams at one point.<br>* And of course, the latest information, from Blizzard saying that all franchises will become MMOGs. Granted, this doesn&#8217;t mean it would happen soon, but with all the evidence supporting Diablo 3, and DMCA&#8217;s I consistently receive for releasing crap, I can see this happening.</p>
+
+<p>There is one thing I did want to address as well. As far as I recall, Blizzard said, upon attending Blizzcon, you would receive a Beta code. If I remember correctly, they also stated the Beta code would not be for the World of Warcraft expansion, but a yet unannounced game release. Two days ago, a Blizzard representative said otherwise, &#8220;..that card is your entrance to play World Of Warcraft expansion before most any one else. I would recommend following the instructions and registering.&#8221; I call bullshit, riot anyone?</p>
+
+<p>Now there is one final determining factor. Will there be a Blizzcon &#8216;06? This of course would play a huge rule on if it&#8217;s announced at the event. If there isn&#8217;t, which is up for debate (and I&#8217;m working on getting confirmation right now), then we may not see it until their next event, as there are no other huge announcements upcoming that I&#8217;m aware of. In my opinion they will save this for their own event, as it makes them a lot more do re me than announcing at E3 would.</p>
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2006-06-13T00:00:00-07:00" pubdate data-updated="true">Jun 13<span>th</span>, 2006</time></div>
+ <div class="tags">
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2006/06/04/some-new-sites-a-new-theory-and-the-tourist">Some New Sites, a New Theory, and the Tourist!</a></h1>
<div class="entry">
<p>So I took a little time and moved my wiki off of World of Warcraft Guru since I won&#8217;t be working on the site anymore. I did this for no reason other than the EULA, as Blizzard doesn&#8217;t support it so it makes WG look bad. Doing this I bought a new domain, and buying a new domain lead me to buying more so I give you&#8230; <a href="http://www.hackwow.com/">HackWOW</a>, <a href="http://www.hackvanguard.com/">HackVanguard</a>, and my personal favorite, <a href="http://www.whatisige.com/">What is IGE</a>.</p>
View
282 blog/page/2/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="Using Arrays as Materialized Paths in Postgres Something we&#8217;ve been casually working on at Disqus for quite some time is an improved &hellip;">
+ <meta name="description" content="Sticking With Standards More and more I&#8217;m seeing the &#8220;requirements.txt pattern&#8221; come up. This generally refers to projects (but &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,164 @@
<article class="post">
+ <h1 class="title"><a href="/2012/04/24/sticking-with-standards">Sticking With Standards</a></h1>
+ <div class="entry">
+ <p>More and more I&#8217;m seeing the &#8220;requirements.txt pattern&#8221; come up. This generally refers to projects (but not just), and
+seems to have started around the same time as Heroku adopting Python. I feel like this is something that matters in the
+Python world, and because I have an opinion on everything, I want to share mine.</p>
+
+
+
+
+<h3>requirements.txt</h3>
+
+
+
+
+<p>Let&#8217;s first talk about what this pattern actually is. As you should already be familiar with pip (if you&#8217;re not, this
+post is not for you), the idea of this is that whatever you&#8217;re doing, is installable by pointing pip at a requirements.txt
+file which contains a list of your projects dependencies. This has some obvious benefits, one being that you can
+mark repositories as dependencies.</p>
+
+
+
+
+<p>Another benefit of this is when you have a large project (like DISQUS) and your dependencies can vary between environments. For
+example, we have several various requirements files for disqus-web (our largest package):</p>
+
+
+
+
+<pre>
+requirements/global.txt
+requirements/production.txt
+requirements/development.txt
+</pre>
+
+
+
+
+<p>These end up being pretty obvious, and when an app has specific needs there&#8217;s no reason not to approach the problem this
+way. That said, you dont <strong>need</strong> to do things this way, and in every project other than our main repository,
+including our open source work, all dependencies are specified completely in setup.py. Even in this case, we could just
+as easily specify our core requirements as part of the package and simply have additional files which label the production
+and development dependencies.</p>
+
+
+
+
+<h3>setup.py is the right choice</h3>
+
+
+
+
+<p>A common argument for not using setup.py is that a library is not the same as an app (or larger project). Why not? We
+employ the same metadata in everything. Each contains a list of dependencies, some various metadata, and possibly a list
+of extra resources (such as scripts, or documentation). Fundamentally they&#8217;re identical. Additionally, if pip is your
+thing, it <strong>does not prevent you from using setup.py</strong>. Let&#8217;s take an example setup.py:</p>
+
+
+
+
+<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
+<span class='line-number'>2</span>
+<span class='line-number'>3</span>
+<span class='line-number'>4</span>
+<span class='line-number'>5</span>
+<span class='line-number'>6</span>
+<span class='line-number'>7</span>
+<span class='line-number'>8</span>
+<span class='line-number'>9</span>
+<span class='line-number'>10</span>
+<span class='line-number'>11</span>
+<span class='line-number'>12</span>
+<span class='line-number'>13</span>
+<span class='line-number'>14</span>
+<span class='line-number'>15</span>
+<span class='line-number'>16</span>
+<span class='line-number'>17</span>
+<span class='line-number'>18</span>
+<span class='line-number'>19</span>
+<span class='line-number'>20</span>
+</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="kn">from</span> <span class="nn">setuptools</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">find_packages</span>
+</span><span class='line'>
+</span><span class='line'><span class="n">requires</span> <span class="o">=</span> <span class="p">[</span>
+</span><span class='line'> <span class="s">&#39;Flask==0.8&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;redis==2.4.11&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;hiredis==0.1.1&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;nydus==0.8.1&#39;</span><span class="p">,</span>
+</span><span class='line'><span class="p">]</span>
+</span><span class='line'>
+</span><span class='line'>
+</span><span class='line'><span class="n">setup</span><span class="p">(</span>
+</span><span class='line'> <span class="n">name</span><span class="o">=</span><span class="s">&#39;something-sexy&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="n">version</span><span class="o">=</span><span class="s">&#39;1.0.0&#39;</span><span class="p">,</span>
+</span><span class='line'> <span class="n">author</span><span class="o">=</span><span class="s">&quot;DISQUS&quot;</span><span class="p">,</span>
+</span><span class='line'> <span class="n">author_email</span><span class="o">=</span><span class="s">&quot;dev@disqus.com&quot;</span><span class="p">,</span>
+</span><span class='line'> <span class="n">package_dir</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;&#39;</span><span class="p">:</span> <span class="s">&#39;src&#39;</span><span class="p">},</span>
+</span><span class='line'> <span class="n">packages</span><span class="o">=</span><span class="n">find_packages</span><span class="p">(</span><span class="s">&quot;src&quot;</span><span class="p">),</span>
+</span><span class='line'> <span class="n">install_requires</span><span class="o">=</span><span class="n">requires</span><span class="p">,</span>
+</span><span class='line'> <span class="n">zip_safe</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
+</span><span class='line'><span class="p">)</span>
+</span></code></pre></td></tr></table></div></figure>
+
+
+
+
+<p>Now, in our case, this is probably a service on Disqus, which means we&#8217;re not listing it as a dependancy. In every
+single scenario we have, we want our package to be on <code>PYTHONPATH</code>, and this is no different. There&#8217;s many ways
+to solve the problem, and generally adjusting <code>sys.path</code> is not what you&#8217;re going to want. Whether you install
+the package or you just run it as an editable package (via pip install -e or setuptool&#8217;s develop command), packaging
+your app makes it that much easier.</p>
+
+
+
+
+<p>What&#8217;s even more important is that you <strong>stick with standards</strong>, especially in our growing ecosystem of
+open source and widely available libraries. There&#8217;s absolutely no reason to have to explain to a developer that they
+need to run some arbitrary command to get your neat tool to install. Following the well defined and adopted standards
+ensures that is never the case.</p>
+
+
+
+
+<p>Keep it simple. Keep it obvious.</p>
+
+
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2012-04-24T22:23:00-07:00" pubdate data-updated="true">Apr 24<span>th</span>, 2012</time></div>
+ <div class="tags">
+
+<div class="cat">
+
+ <a class='category' href='/categories/disqus/'>disqus</a>, <a class='category' href='/categories/django/'>django</a>, <a class='category' href='/categories/python/'>python</a>
+
+</div>
+
+</div>
+
+ <span class="comments"><a href="/2012/04/24/sticking-with-standards#disqus_thread">Comments</a></span>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2012/04/08/using-arrays-as-materialized-paths-in-postgres">Using Arrays as Materialized Paths in Postgres</a></h1>
<div class="entry">
<p>Something we&#8217;ve been casually working on at Disqus for <a href="http://justcramer.com/2010/05/30/scaling-threaded-comments-on-django-at-disqus/">quite some time</a> is an improved pagination method for threaded comments. This is obviously pretty important to us, it drives the very foundation of our product. It also happens to be an area that&#8217;s somewhat challenging, and has a <a href="http://en.wikipedia.org/wiki/Nested_intervals">wide</a> <a href="http://en.wikipedia.org/wiki/Nested_set_model">array</a> <a href="http://en.wikipedia.org/wiki/Adjacency_list">of</a> <a href="https://communities.bmc.com/communities/docs/DOC-9902">solutions</a>. In the end, this is an overly complicated solution to solve the problem of threads having 10s or 100s of thousands of comments.</p>
@@ -1215,128 +1373,6 @@ <h1 class="title"><a href="/2011/02/08/using-os-x-media-keys-in-rdio-desktop">Us
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2011/01/25/error-tracing-in-sentry">Error Tracing in Sentry</a></h1>
- <div class="entry">
- <p>A few weeks ago we pushed out an update to <a href="http://github.com/dcramer/django-sentry">Sentry</a>, bumping it&#8217;s version to 1.6.0. Among the changes was a new &#8220;Sentry ID&#8221; value which is created by the client, rather than relying on the server. This seems like something insignificant, but it allows you to do something very powerful: trace errors from the customer or developer down to the precise request and log entry.</p>
-
-<h4>Exposing Sentry ID</h4>
-
-<p>The new IDs are generated automatically when a message is processed (by the client), so you won&#8217;t need to make any changes on that end. Likely, however, you&#8217;re going to want to expose these at your application level for a couple of different reasons. The first one we&#8217;re going to cover is your customer&#8217;s experience.</p>
-
-<p>The easiest way to expose this information in a useful manner, is by <strong>creating a modified 500.html</strong>. In DISQUS&#8217; case, we mention the error reference ID to the end-user, so that when they&#8217;re reporting a problem they can pass along this information.</p>
-
-<h5>Create a custom 500 handler</h5>
-
-<p>The first thing you&#8217;re going to need to do is to create a custom 500 handler. This defined in <code>urls.py</code>, so we&#8217;re just going to go ahead and create the view in-place.</p>
-
-<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
-<span class='line-number'>2</span>
-<span class='line-number'>3</span>
-<span class='line-number'>4</span>
-<span class='line-number'>5</span>
-<span class='line-number'>6</span>
-<span class='line-number'>7</span>
-<span class='line-number'>8</span>
-<span class='line-number'>9</span>
-<span class='line-number'>10</span>
-<span class='line-number'>11</span>
-<span class='line-number'>12</span>
-<span class='line-number'>13</span>
-<span class='line-number'>14</span>
-<span class='line-number'>15</span>
-<span class='line-number'>16</span>
-<span class='line-number'>17</span>
-<span class='line-number'>18</span>
-<span class='line-number'>19</span>
-</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">def</span> <span class="nf">handler500</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
-</span><span class='line'> <span class="sd">&quot;&quot;&quot;</span>
-</span><span class='line'><span class="sd"> An error handler which exposes the request object to the error template.</span>
-</span><span class='line'><span class="sd"> &quot;&quot;&quot;</span>
-</span><span class='line'> <span class="kn">from</span> <span class="nn">django.template</span> <span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">loader</span>
-</span><span class='line'> <span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseServerError</span>
-</span><span class='line'> <span class="kn">from</span> <span class="nn">disqus.context_processors</span> <span class="kn">import</span> <span class="n">default</span>
-</span><span class='line'> <span class="kn">import</span> <span class="nn">logging</span>
-</span><span class='line'> <span class="kn">import</span> <span class="nn">sys</span>
-</span><span class='line'> <span class="k">try</span><span class="p">:</span>
-</span><span class='line'> <span class="n">context</span> <span class="o">=</span> <span class="n">default</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
-</span><span class='line'> <span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
-</span><span class='line'> <span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exc_info</span><span class="o">=</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">(),</span> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;request&#39;</span><span class="p">:</span> <span class="n">request</span><span class="p">})</span>
-</span><span class='line'> <span class="n">context</span> <span class="o">=</span> <span class="p">{}</span>
-</span><span class='line'>
-</span><span class='line'> <span class="n">context</span><span class="p">[</span><span class="s">&#39;request&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">request</span>
-</span><span class='line'>
-</span><span class='line'> <span class="n">t</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="s">&#39;500.html&#39;</span><span class="p">)</span> <span class="c"># You need to create a 500.html template.</span>
-</span><span class='line'> <span class="k">return</span> <span class="n">HttpResponseServerError</span><span class="p">(</span><span class="n">t</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">Context</span><span class="p">(</span><span class="n">context</span><span class="p">)))</span>
-</span></code></pre></td></tr></table></div></figure>
-
-<p>We&#8217;re going to expose the request object to our 500.html in the above. Keep in mind, that doing this allows you to add some logic into your template, and you&#8217;re going to need to be very careful that this logic can&#8217;t raise a new exception.</p>
-
-<h5>Tweaking your 500.html</h5>
-
-<p>The next thing you&#8217;ll need to do is to tweak your 500.html template to actually show the Sentry ID. Assuming the request object was passed into Sentry, it will attach the last error seen under <code>request.sentry['id']</code>. Given this, we can easily report it to the end-user in our template:</p>
-
-<pre>
-&lt;p&gt;The Disqus team has been alerted and we're on the case. For more information, check out &lt;a href="http://status.disqus.com"&gt;Disqus Status &raquo;&lt;/a&gt;&lt;/p&gt;
-&#123;% if request.sentry.id %&#125;
- &lt;p&gt;If you need assistance, you may reference this error as &lt;strong&gt;&#123;&#123; request.sentry.id &#125;&#125;&lt;/strong&gt;.&lt;/p&gt;
-&#123;% endif %&#125;
-</pre>
-
-<h4>Sentry ID as a response header</h4>
-
-<p>The other quick solution to get access to this variable is simply by enabling an included response middleware, <code>SentryResponseErrorIdMiddleware</code>. Just pop open your <code>settings.py</code> and append it to your <code>MIDDLEWARE_CLASSES</code>:</p>
-
-<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
-<span class='line-number'>2</span>
-<span class='line-number'>3</span>
-<span class='line-number'>4</span>
-</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">MIDDLEWARE_CLASSES</span> <span class="o">=</span> <span class="p">(</span>
-</span><span class='line'> <span class="o">...</span><span class="p">,</span>
-</span><span class='line'> <span class="s">&#39;sentry.client.middleware.SentryResponseErrorIdMiddleware&#39;</span><span class="p">,</span>
-</span><span class='line'><span class="p">)</span>
-</span></code></pre></td></tr></table></div></figure>
-
-<p>Now if you check your response headers after hitting an error, you should see <code>X-Sentry-ID</code>.</p>
-
-<h4>Find errors by ID</h4>
-
-<p>Sentry makes it very easy to pull up error messages by ID. The one requirement is that you&#8217;re going to need to ensure <code>sentry.filters.SearchFilter</code> is included within <code>SENTRY_FILTERS</code> (it&#8217;s enabled by default). Once done, Sentry will discover if you&#8217;re entering a UUID hex value (the Sentry ID) in the search box, and it will jump directly to that error&#8217;s page.</p>
-
-<p><img src="http://f.cl.ly/items/2f1s1X0J231F2F3u0V0d/sentry-id.png"/></p>
-
-<p>You&#8217;ll also notice that all messages are now tagged with their unique Sentry ID as well (per the screenshot).</p>
-
-
- </div>
- <div class="meta">
- <div class="date">
-
-
-
-
-
-
-
-
-
-
-
-<time datetime="2011-01-25T00:00:00-08:00" pubdate data-updated="true">Jan 25<span>th</span>, 2011</time></div>
- <div class="tags">
-
-<div class="cat">
-
- <a class='category' href='/categories/disqus/'>disqus</a>, <a class='category' href='/categories/django/'>django</a>, <a class='category' href='/categories/sentry/'>sentry</a>
-
-</div>
-
-</div>
-
- </div>
-</article>
-
<nav id="pagenavi">
<a href="/" class="prev">Prev</a>
View
219 blog/page/3/index.html
@@ -7,7 +7,7 @@
<meta name="author" content="David Cramer">
- <meta name="description" content="Settings in Django I want to talk a bit about how we handle our large amounts of application configuration over at DISQUS. Every app has it, and it &hellip;">
+ <meta name="description" content="Error Tracing in Sentry A few weeks ago we pushed out an update to Sentry, bumping it&#8217;s version to 1.6.0. Among the changes was a new &#8220; &hellip;">
<meta name="viewport" content="width=device-width; initial-scale=1; maximum-scale=1">
@@ -71,6 +71,128 @@
<article class="post">
+ <h1 class="title"><a href="/2011/01/25/error-tracing-in-sentry">Error Tracing in Sentry</a></h1>
+ <div class="entry">
+ <p>A few weeks ago we pushed out an update to <a href="http://github.com/dcramer/django-sentry">Sentry</a>, bumping it&#8217;s version to 1.6.0. Among the changes was a new &#8220;Sentry ID&#8221; value which is created by the client, rather than relying on the server. This seems like something insignificant, but it allows you to do something very powerful: trace errors from the customer or developer down to the precise request and log entry.</p>
+
+<h4>Exposing Sentry ID</h4>
+
+<p>The new IDs are generated automatically when a message is processed (by the client), so you won&#8217;t need to make any changes on that end. Likely, however, you&#8217;re going to want to expose these at your application level for a couple of different reasons. The first one we&#8217;re going to cover is your customer&#8217;s experience.</p>
+
+<p>The easiest way to expose this information in a useful manner, is by <strong>creating a modified 500.html</strong>. In DISQUS&#8217; case, we mention the error reference ID to the end-user, so that when they&#8217;re reporting a problem they can pass along this information.</p>
+
+<h5>Create a custom 500 handler</h5>
+
+<p>The first thing you&#8217;re going to need to do is to create a custom 500 handler. This defined in <code>urls.py</code>, so we&#8217;re just going to go ahead and create the view in-place.</p>
+
+<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
+<span class='line-number'>2</span>
+<span class='line-number'>3</span>
+<span class='line-number'>4</span>
+<span class='line-number'>5</span>
+<span class='line-number'>6</span>
+<span class='line-number'>7</span>
+<span class='line-number'>8</span>
+<span class='line-number'>9</span>
+<span class='line-number'>10</span>
+<span class='line-number'>11</span>
+<span class='line-number'>12</span>
+<span class='line-number'>13</span>
+<span class='line-number'>14</span>
+<span class='line-number'>15</span>
+<span class='line-number'>16</span>
+<span class='line-number'>17</span>
+<span class='line-number'>18</span>
+<span class='line-number'>19</span>
+</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">def</span> <span class="nf">handler500</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
+</span><span class='line'> <span class="sd">&quot;&quot;&quot;</span>
+</span><span class='line'><span class="sd"> An error handler which exposes the request object to the error template.</span>
+</span><span class='line'><span class="sd"> &quot;&quot;&quot;</span>
+</span><span class='line'> <span class="kn">from</span> <span class="nn">django.template</span> <span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">loader</span>
+</span><span class='line'> <span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseServerError</span>
+</span><span class='line'> <span class="kn">from</span> <span class="nn">disqus.context_processors</span> <span class="kn">import</span> <span class="n">default</span>
+</span><span class='line'> <span class="kn">import</span> <span class="nn">logging</span>
+</span><span class='line'> <span class="kn">import</span> <span class="nn">sys</span>
+</span><span class='line'> <span class="k">try</span><span class="p">:</span>
+</span><span class='line'> <span class="n">context</span> <span class="o">=</span> <span class="n">default</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
+</span><span class='line'> <span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
+</span><span class='line'> <span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exc_info</span><span class="o">=</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">(),</span> <span class="n">extra</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;request&#39;</span><span class="p">:</span> <span class="n">request</span><span class="p">})</span>
+</span><span class='line'> <span class="n">context</span> <span class="o">=</span> <span class="p">{}</span>
+</span><span class='line'>
+</span><span class='line'> <span class="n">context</span><span class="p">[</span><span class="s">&#39;request&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">request</span>
+</span><span class='line'>
+</span><span class='line'> <span class="n">t</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="s">&#39;500.html&#39;</span><span class="p">)</span> <span class="c"># You need to create a 500.html template.</span>
+</span><span class='line'> <span class="k">return</span> <span class="n">HttpResponseServerError</span><span class="p">(</span><span class="n">t</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">Context</span><span class="p">(</span><span class="n">context</span><span class="p">)))</span>
+</span></code></pre></td></tr></table></div></figure>
+
+<p>We&#8217;re going to expose the request object to our 500.html in the above. Keep in mind, that doing this allows you to add some logic into your template, and you&#8217;re going to need to be very careful that this logic can&#8217;t raise a new exception.</p>
+
+<h5>Tweaking your 500.html</h5>
+
+<p>The next thing you&#8217;ll need to do is to tweak your 500.html template to actually show the Sentry ID. Assuming the request object was passed into Sentry, it will attach the last error seen under <code>request.sentry['id']</code>. Given this, we can easily report it to the end-user in our template:</p>
+
+<pre>
+&lt;p&gt;The Disqus team has been alerted and we're on the case. For more information, check out &lt;a href="http://status.disqus.com"&gt;Disqus Status &raquo;&lt;/a&gt;&lt;/p&gt;
+&#123;% if request.sentry.id %&#125;
+ &lt;p&gt;If you need assistance, you may reference this error as &lt;strong&gt;&#123;&#123; request.sentry.id &#125;&#125;&lt;/strong&gt;.&lt;/p&gt;
+&#123;% endif %&#125;
+</pre>
+
+<h4>Sentry ID as a response header</h4>
+
+<p>The other quick solution to get access to this variable is simply by enabling an included response middleware, <code>SentryResponseErrorIdMiddleware</code>. Just pop open your <code>settings.py</code> and append it to your <code>MIDDLEWARE_CLASSES</code>:</p>
+
+<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
+<span class='line-number'>2</span>
+<span class='line-number'>3</span>
+<span class='line-number'>4</span>
+</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="n">MIDDLEWARE_CLASSES</span> <span class="o">=</span> <span class="p">(</span>
+</span><span class='line'> <span class="o">...</span><span class="p">,</span>
+</span><span class='line'> <span class="s">&#39;sentry.client.middleware.SentryResponseErrorIdMiddleware&#39;</span><span class="p">,</span>
+</span><span class='line'><span class="p">)</span>
+</span></code></pre></td></tr></table></div></figure>
+
+<p>Now if you check your response headers after hitting an error, you should see <code>X-Sentry-ID</code>.</p>
+
+<h4>Find errors by ID</h4>
+
+<p>Sentry makes it very easy to pull up error messages by ID. The one requirement is that you&#8217;re going to need to ensure <code>sentry.filters.SearchFilter</code> is included within <code>SENTRY_FILTERS</code> (it&#8217;s enabled by default). Once done, Sentry will discover if you&#8217;re entering a UUID hex value (the Sentry ID) in the search box, and it will jump directly to that error&#8217;s page.</p>
+
+<p><img src="http://f.cl.ly/items/2f1s1X0J231F2F3u0V0d/sentry-id.png"/></p>
+
+<p>You&#8217;ll also notice that all messages are now tagged with their unique Sentry ID as well (per the screenshot).</p>
+
+
+ </div>
+ <div class="meta">
+ <div class="date">
+
+
+
+
+
+
+
+
+
+
+
+<time datetime="2011-01-25T00:00:00-08:00" pubdate data-updated="true">Jan 25<span>th</span>, 2011</time></div>
+ <div class="tags">
+
+<div class="cat">
+
+ <a class='category' href='/categories/disqus/'>disqus</a>, <a class='category' href='/categories/django/'>django</a>, <a class='category' href='/categories/sentry/'>sentry</a>
+
+</div>
+
+</div>
+
+ </div>
+</article>
+
+
+ <article class="post">
<h1 class="title"><a href="/2011/01/13/settings-in-django">Settings in Django</a></h1>
<div class="entry">
<p>I want to talk a bit about how we handle our large amounts of application configuration over at DISQUS. Every app has it, and it seems like theres a hundred different ways that you can manage it. While I&#8217;m not going to say ours is the best way, it has allowed us a very flexible application config under our varying situations.</p>
@@ -1045,101 +1167,6 @@ <h1 class="title"><a href="/2010/11/30/integrating-pyflakes-into-textmate">Integ
</div>
</article>
-
- <article class="post">
- <h1 class="title"><a href="/2010/10/19/keeping-your-logging-compatible-with-sentry">Keeping Your Logging Compatible With Sentry</a></h1>
- <div class="entry">
- <p>Something I&#8217;ve noticed while digging around in various libraries, is the inconsistent use of logging. This creates some problems with <a href="http://github.com/dcramer/django-sentry">Sentry</a>, and in the end gives us some very ugly exception logging.</p>
-
-<p>Let&#8217;s take a simple example (we&#8217;re going to use Celery for this one):</p>
-
-<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
-<span class='line-number'>2</span>
-<span class='line-number'>3</span>
-<span class='line-number'>4</span>
-<span class='line-number'>5</span>
-<span class='line-number'>6</span>
-<span class='line-number'>7</span>
-<span class='line-number'>8</span>
-</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="k">if</span> <span class="n">task</span><span class="o">.</span><span class="n">eta</span><span class="p">:</span>
-</span><span class='line'> <span class="k">try</span><span class="p">:</span>
-</span><span class='line'> <span class="n">eta</span> <span class="o">=</span> <span class="n">to_timestamp</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">eta</span><span class="p">)</span>
-</span><span class='line'> <span class="k">except</span> <span class="ne">OverflowError</span><span class="p">,</span> <span class="n">exc</span><span class="p">:</span>
-</span><span class='line'> <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span>
-</span><span class='line'> <span class="s">&quot;Couldn&#39;t convert eta </span><span class="si">%s</span><span class="s"> to timestamp: </span><span class="si">%r</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span>
-</span><span class='line'> <span class="n">task</span><span class="o">.</span><span class="n">eta</span><span class="p">,</span> <span class="n">exc</span><span class="p">))</span>
-</span><span class='line'><span class="n">task</span><span class="o">.</span><span class="n">acknowledge</span><span class="p">()</span>
-</span></code></pre></td></tr></table></div></figure>
-
-The functionality is pretty obvious. The logger is set via something similar to:
-
-<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
-</pre></td><td class='code'><pre><code class='python'><span class='line'><span class="bp">self</span><span class="o">.</span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s">&#39;celery&#39;</span><span class="p">)</span>
-</span></code></pre></td></tr></table></div></figure>
-
-<p>Now the big issue with this, is it doesnt use the standardized logging storage for exceptions. This isn&#8217;t an issue if you&#8217;re logging to a text file, or something that just streams the messages, but once you start using something as powerful as Sentry, it is. To fix this, we need to make one simple adjustment:</p>
-
-<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
-<span class='line-number'>2</span>
-<span