<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Python | Musings of an Anonymous Geek</title>
	<atom:link href="http://protocolostomy.com/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>https://protocolostomy.com</link>
	<description>Made with only the finest 1&#039;s and 0&#039;s</description>
	<lastBuildDate>Thu, 06 May 2021 14:25:11 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>
<site xmlns="com-wordpress:feed-additions:1">2259962</site>	<item>
		<title>User Activation With Django and Djoser</title>
		<link>https://protocolostomy.com/2021/05/06/user-activation-with-django-and-djoser/</link>
					<comments>https://protocolostomy.com/2021/05/06/user-activation-with-django-and-djoser/#respond</comments>
		
		<dc:creator><![CDATA[jonesy]]></dc:creator>
		<pubDate>Thu, 06 May 2021 14:25:09 +0000</pubDate>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Technology]]></category>
		<guid isPermaLink="false">https://protocolostomy.com/?p=1063</guid>

					<description><![CDATA[<p>Depending on the project, Django and Djoser can go really well together. Django provides such an enormous feature set as a foundation, and such a modular platform, that tools like Djoser can provide enormous value while still staying out of the way of the rest of your application. At the same time, the whole solution...</p>
The post <a href="https://protocolostomy.com/2021/05/06/user-activation-with-django-and-djoser/">User Activation With Django and Djoser</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></description>
										<content:encoded><![CDATA[<p>Depending on the project, Django and Djoser can go really well together. Django provides such an enormous feature set as a foundation, and such a modular platform, that tools like Djoser can provide enormous value while still staying out of the way of the rest of your application. At the same time, the whole solution (Django, Djoser, and  any other reusable Django app I&#8217;ve ever seen), top to bottom, is Just Python™.  That means you can almost always find the right place to hook in your own code, without having to take over responsibility for an entire solution. </p>



<p>Djoser is a library that integrates nicely into a Django REST Framework project to provide API endpoints for things like user registration, login and logout, password resets, etc. It also integrates pretty seamlessly with Django-SimpleJWT to enable JWT support, and will expose JWT create, refresh, and verify endpoints if support is turned on. It&#8217;s pretty sweet. </p>



<p>Well&#8230;. most of the time. </p>



<p>The only real issues I&#8217;ve had with Djoser always root from one of two assumptions the project makes: </p>



<ol class="wp-block-list"><li>That you&#8217;re puritanical in your adherence to REST principles at every turn, and </li><li>That you&#8217;re building a Single Page Application (SPA)</li></ol>



<p>That first one is easily forgivable: if you&#8217;re going to be an opinionated solution, it&#8217;s best to be consistent, and strict. The minute you fall off of that wagon, everything starts to devolve into murkiness. It doesn&#8217;t seem like a big leap to say that a lot of developers prefer an API that is clear and consistent over one that is vague and inconsistent. </p>



<p>As for the second assumption, it honestly doesn&#8217;t get in the way very often, but on a recent project, it bit me pretty hard. On this project, I had to leverage Djoser in my Django project&#8217;s user activation flow. </p>



<h2 class="wp-block-heading">User Registration and User Activation</h2>



<p>User activation happens as part of the user registration process in my case (and, I suspect, most cases). At a high level, the registration flow goes like this: </p>



<ol class="wp-block-list"><li>a POST is sent to the server requesting that a given username or email be given a user account, using the given password. </li><li>the server generates a token of some kind, uses that token to generate a verification link, and sends an account activation email containing the link. </li><li>the end user opens the email and clicks the link</li><li>magic</li><li>the user is activated, and may or may not get an email confirming that their account is ready to go</li></ol>



<p>All of this is straightforward until you get to step 4: &#8216;magic&#8217;. Big surprise, right? Also perhaps unsurprising is that this is where Djoser&#8217;s assumptions make life difficult if you&#8217;re not building a Single Page Application, and/or are not a REST purist. </p>



<h2 class="wp-block-heading">Djoser User Registration</h2>



<p>Before getting to activation, you have to register. For completeness, it&#8217;s worth pointing out that Djoser provides an endpoint that takes a POST request with the desired username, email, and password to kick things off. It integrates nicely with the rest of your application without any real work to do other than adding a urlpattern that&#8217;s given to you to your urls.py file. </p>



<p>In my case, I&#8217;m using a custom user model and I changed the USERNAME_FIELD to &#8217;email&#8217;, and as a result, Djoser accepts just the email and password fields by default, because it&#8217;s leaning on the base Django functionality for as much as possible, which is smart and makes everyones&#8217; lives easier. </p>



<p>When this POST request comes in, password validators and any other things you have set up to happen at user creation time will happen, including the creation of a user record. However, the <code>is_active</code> flag will be <code>False</code> for that record. Then it generates an encoded uid (from the record it created) and a verification token, uses them along with the value of ACTIVATION_URL to form a confirmation link, puts that in an email to the email address used to register, and sends it. And that leads us to&#8230;</p>



<h2 class="wp-block-heading">Djoser User Activation</h2>



<p>First, let&#8217;s have a look at the default value for Djoser&#8217;s ACTIVATION_URL setting. This setting determines the URL that will be emailed to the person who is trying to register a new account. The default value is `</p>



<pre class="wp-block-preformatted">'#/activate/{uid}/{token}'`</pre>



<p>This is a front end URL with placeholders for the uid and token values. It gets assembled into an account registration verification link that looks like this: </p>



<p><code>http://localhost:8000/#/activate/Mw/am6c7b-85f2acbaf4691e9cc6c891bbc4fd7754</code></p>



<p>Up to this point in my project, I was gleefully following along with what Djoser seems to be making easy for me. Then I clicked the above link and everything crashed. Why? Because Djoser does not have a back end view to handle the front end URL that is the default ACTIVATION_URL. </p>



<p>Here&#8217;s the explanation from one of the project maintainers: <a href="https://github.com/sunscrapers/djoser/issues/14" target="_blank" rel="noreferrer noopener">https://github.com/sunscrapers/djoser/issues/14</a>  </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>I suppose you directly use an url to <a href="https://github.com/sunscrapers/djoser/blob/master/djoser/views.py#L173">activation view</a> which <a href="https://github.com/sunscrapers/djoser/blob/master/djoser/utils.py#L39">expects POST request</a>. When you open a link to this view in browser it makes a GET request which is simply not working.</p><p>Our assumption is that GET requests should not change the state of application. That&#8217;s why the activation view expects POST in order to affect user model. Moreover it&#8217;s REST API so if you open one of the endpoints in your browser it displays JSON response which is not something for regular user.</p><p>If you&#8217;re working on single page application you need to create a new screen with separate url that generates POST request to your REST API.</p><p>If you really want to have view that activates user on GET request then you need to implement your own view, but remember to provide reasonable html response.</p></blockquote>



<p>To boil this down, my understanding from this is that:</p>



<ol class="wp-block-list"><li>Djoser devs know that the ACTIVATION_URL is going to be used to create a link that is sent to someone via email.</li><li>Djoser devs know that, when you click a link in an email, the result is a GET request to the back end. </li><li>Djoser devs have provided a view for user activation that only supports POST requests in spite of this fact.</li></ol>



<p>This is immensely frustrating. Their implementation seems to sacrifice a product that actually works at all for the sake of REST purity and maybe an assumption that all developers are only creating SPAs. What&#8217;s more, searching around for solutions turns up lots of confused people. The solution that I found trending was one where you write your own view that <em>does</em> accept a GET request, and then, inside the view, in the back end code, make a POST request to run the code in Djoser&#8217;s UserActivationView! </p>



<p>This all just felt way too&#8230; wrong for me. The back end should not make an HTTP request to itself. Perhaps what I did wasn&#8217;t 100% perfect either, but I&#8217;d be interested in a dialog that could shed more light on why things are the way they are, and how to properly and effectively deal with it. </p>



<h2 class="wp-block-heading" id="my-workaround">My Workaround</h2>



<p>First, if you&#8217;re just here for the code, here&#8217;s the view I created and the urlpattern that maps to it. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: python; title: ; notranslate">
from djoser.views import UserViewSet
from rest_framework.response import Response

class ActivateUser(UserViewSet):
    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        kwargs.setdefault(&#039;context&#039;, self.get_serializer_context())

        # this line is the only change from the base implementation.
        kwargs&#x5B;&#039;data&#039;] = {&quot;uid&quot;: self.kwargs&#x5B;&#039;uid&#039;], &quot;token&quot;: self.kwargs&#x5B;&#039;token&#039;]}

        return serializer_class(*args, **kwargs)

    def activation(self, request, uid, token, *args, **kwargs):
        super().activation(request, *args, **kwargs)
        return Response(status=status.HTTP_204_NO_CONTENT)
</pre></div>


<p>My Djoser ACTIVATION_URL in settings.py is `</p>



<pre class="wp-block-preformatted">'accounts/activate/{uid}/{token}'</pre>



<p>And then the urlpattern used to map requests to that url looks like this: </p>



<pre class="wp-block-preformatted">path('accounts/activate/&lt;uid&gt;/&lt;token&gt;', ActivateUser.as_view({'get': 'activation'}), name='activation'),</pre>



<h2 class="wp-block-heading">What&#8217;s Actually Happening In My Workaround</h2>



<p>Djoser leans on Django and Django Rest Framework for a lot of its functionality. In order to support a large number of URLs while duplicating the least amount of code, Djoser utilizes Django Rest Framework&#8217;s &#8216;ViewSet&#8217; concept, which lets you map an &#8216;action&#8217; to a method in a single class. So, instead of having separate views for &#8220;UserRegistration&#8221;, &#8220;UserActivation&#8221;, &#8220;UserPasswordChange&#8221;, and all of the other things that can happen to a user, Djoser just has one class called &#8220;UserViewSet&#8221; (at <code>djoser.views.UserViewSet</code>). </p>



<p>UserViewSet.activation is a method that takes a POST request containing the UID and token values, validates them, and (assuming validation passes) sends a signal that, in my application, sets the <code>is_active</code> flag on the user to <code>True</code> and sends the new user an email letting them know their account is now active. &#8220;It&#8217;s all perfect except for the POST!&#8221; I thought. But I wasn&#8217;t happy with solutions that have code in the back end going back out to the internet to trigger other code on the back end. I wasn&#8217;t going to accept sending a POST request to trigger another view. </p>



<p>So, step one was to create my own view, inheriting from UserViewSet, and then allowing that view to accept a GET request, because you&#8217;ll recall that our mission is to handle the user clicking the link in their email to activate their account. Aside from accepting a GET request, I don&#8217;t really want my code to do anything at all. Just call super().activation and get out of the way! </p>



<p>Now, the base implementation forces POST-only by decorating it with an <code>@action</code> decorator. The first argument to the decorator is a list of HTTP methods supported, and only <code>post</code> is listed. Great! So just don&#8217;t decorate that method, map it to a GET in <code>urls.py</code>, and you&#8217;re all set!</p>



<p>Sadly, it was not quite that easy. Since UserViewSet.activation only supports a POST request, it also assumes that what it needs is already in <code>request.data</code>. But when our GET request comes in, the <code>uid</code> and <code>token</code> values will be in <code>kwargs</code>. Making things more difficult, the <code>request</code> object here is Django Rest Framework&#8217;s <code>Request</code> object, and its <code>data</code> attribute is not settable (I think it&#8217;s a property defined with no setter, but don&#8217;t quote me). So, I can&#8217;t just overwrite <code>request.data</code> and move on. Now what? </p>



<p>So, we need to find a way to get data into <code>request.data</code> so that when I call <code>super().activation()</code>, it can act on that data. In looking at the code for <code>UserViewSet.activation</code> I found this: </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: python; title: ; notranslate">
    @action(&#x5B;&quot;post&quot;], detail=False)
    def activation(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
</pre></div>


<p>That&#8217;s not the whole method, but for the whole method, the only time <code>request.data</code> is referenced is on the very first line of the code. Since we already said I can&#8217;t just shim in a line and overwrite <code>request.data</code>, let&#8217;s instead have a look at this <code>get_serializer</code> method! </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: python; title: ; notranslate">
    def get_serializer(self, *args, **kwargs):
        &quot;&quot;&quot;
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        &quot;&quot;&quot;
        serializer_class = self.get_serializer_class()
        kwargs.setdefault(&#039;context&#039;, self.get_serializer_context())
        return serializer_class(*args, **kwargs)
</pre></div>


<p>Notice that it doesn&#8217;t explicitly have a <code>data</code> parameter defined in the method&#8217;s signature. That means any reference to <code>data</code> would have to be in <code>kwargs</code>. That means we can set <code>kwargs['data']</code> inside of this method to whatever we want. The updated method to make that happen only adds a single line:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: python; highlight: [4]; title: ; notranslate">
    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        kwargs.setdefault(&#039;context&#039;, self.get_serializer_context())
        kwargs&#x5B;&#039;data&#039;] = {&quot;uid&quot;: self.kwargs&#x5B;&#039;uid&#039;], &quot;token&quot;: self.kwargs&#x5B;&#039;token&#039;]}

        return serializer_class(*args, **kwargs)
</pre></div>


<p>That&#8217;s it. You just effectively replaced <code>request.data</code>. </p>



<h2 class="wp-block-heading">One More Time</h2>



<p>This is a lot. Let&#8217;s review what happened. </p>



<p>First, the mission: </p>



<ul class="wp-block-list"><li>Support a GET request that happens when the user clicks the account activation link in their email. </li></ul>



<p>Next, the problem:</p>



<ul class="wp-block-list"><li>There&#8217;s code to handle user activation, but it doesn&#8217;t support a GET request. </li></ul>



<p>Then, the workaround:</p>



<ul class="wp-block-list"><li>Create our own view that inherits from the Djoser UserViewSet to handle the incoming GET request. </li><li>Override the <code>activation</code> method to accept the <code>uid</code> and <code>token</code> parameters coming in on the URL and remove the <code>@action</code> decorator that only allowed HTTP POST. </li><li>Override the <code>get_serializer</code> method to insert the <code>uid</code> and <code>token</code> values into its <code>kwargs['data']</code>. </li><li>Define a urlpattern that maps a get request to our ACTIVATION_URL to our newly-created view. </li><li>Profit</li></ul>



<p>If you don&#8217;t recall any of the above steps from the discussion, <a href="#my-workaround">scroll back up to see my code</a> in the My Workaround section. </p>



<h2 class="wp-block-heading">But Maybe I&#8217;m Wrong!</h2>



<p>I&#8217;m wrong a lot. Maybe you know better. I&#8217;d be happy to see a better alternative solution. I&#8217;d also love to have a better understanding of the logic Djoser is using, because I admittedly just don&#8217;t get that. As a developer, I&#8217;m far more comfortable moving from APIs back towards the operating system and infrastructure services than I am moving into front end frameworks (though I do have to do that sometimes). So, if you understand how a &#8216;front end url&#8217; is sent via email and then expected to somehow be intercepted by a front end that then sends a POST to the back end, please point me to some docs! </p>



<p></p>The post <a href="https://protocolostomy.com/2021/05/06/user-activation-with-django-and-djoser/">User Activation With Django and Djoser</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></content:encoded>
					
					<wfw:commentRss>https://protocolostomy.com/2021/05/06/user-activation-with-django-and-djoser/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1063</post-id>	</item>
		<item>
		<title>What I&#8217;ve Been Up To</title>
		<link>https://protocolostomy.com/2012/08/05/what-ive-been-up-to/</link>
					<comments>https://protocolostomy.com/2012/08/05/what-ive-been-up-to/#respond</comments>
		
		<dc:creator><![CDATA[bkjones]]></dc:creator>
		<pubDate>Mon, 06 Aug 2012 02:02:09 +0000</pubDate>
				<category><![CDATA[Big Ideas]]></category>
		<category><![CDATA[Me stuff]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">http://protocolostomy.com/?p=995</guid>

					<description><![CDATA[<p>Historically, I post fairly regularly on this blog, but I haven&#8217;t been lately. It&#8217;s not for lack of anything to write about, but rather a lack of time to devote to blogging. I want to post at greater length about some of the stuff I&#8217;ve been doing, and I have several draft posts, but I...</p>
The post <a href="https://protocolostomy.com/2012/08/05/what-ive-been-up-to/">What I’ve Been Up To</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></description>
										<content:encoded><![CDATA[<p>Historically, I post fairly regularly on this blog, but I haven&#8217;t been lately. It&#8217;s not for lack of anything to write about, but rather a lack of time to devote to blogging. I want to post at greater length about some of the stuff I&#8217;ve been doing, and I have several draft posts, but I wanted to list what I&#8217;ve been up to for two reasons:</p>
<ol>
<li>I use my blog as a sort of informal record of what I accomplished over the course of the year, hurdles I ran into, etc. I also sometimes use it to start a dialog about something, or to &#8216;think out loud&#8217; about ideas. So it&#8217;s partially for my own reference.</li>
<li>Someone might actually be interested in something I&#8217;m doing and want to pitch in, fork a repo, point me at an existing tool I&#8217;m reinventing, give me advice, or actually make use of something I&#8217;ve done or something I&#8217;ve learned and can share.</li>
</ol>
<h3>PyCon 2013</h3>
<p>I&#8217;m participating again for the third year in the Program Committee and anywhere else I can help out (time permitting) with the organization of PyCon. It&#8217;s historically been a fantastic and really rewarding experience that <a href="https://us.pycon.org/2013/about/volunteers/">I highly (and sometimes loudly) recommend</a> to anyone who will listen. Some day I want to post at greater length about some actual instances where being really engaged in the community has been a win in real, practical ways. For now, you&#8217;ll have to take my word for it. It&#8217;s awesome.</p>
<p>I also hope to submit a talk for PyCon 2013. Anyone considering doing this should know a couple of things about it:</p>
<ol>
<li>Even though I participate in the Program Committee, which is a completely volunteer committee that takes on the somewhat grueling process of selecting the talks, tutorials, and poster sessions, it&#8217;s pretty much unrelated to my chances of having my talk accepted. In other words, submitting a talk is as daunting for me as it is for anyone. Maybe more so.</li>
<li>Giving a talk was a really rewarding experience, and I recommend to anyone to <a href="https://us.pycon.org/2013/speaking/speakatpycon/">give it a shot</a>.</li>
</ol>
<p>I just published a <a href="https://protocolostomy.com/2012/08/05/pycon-talk-proposals-all-you-need-to-know-and-more/">really long post about submitting a talk to PyCon</a>. It&#8217;s full of completely unsolicited advice and subjective opinions about the do&#8217;s and don&#8217;ts of talk submission, based on my experiences as both a submitter of proposals and a member of the Program Committee, which is the committee that selects the talks.</p>
<h3>Python Cookbook</h3>
<p>Dave Beazley and I are really rolling with the next edition of the Python Cookbook, which will cover Python 3 *only*. We had some initial drama with it, but the good news is that I feel that Dave and I have shared a common vision for the book since just about day one, and that shared vision hasn&#8217;t changed, and O&#8217;Reilly hasn&#8217;t forced our hand to change it, which means the book should be a really good reflection of that vision when it&#8217;s actually released. I should note, however, that the next edition will represent a pretty dramatic departure from the form and function of previous versions. I&#8217;m excited for everyone to see it, but that&#8217;s going to have to wait for a bit. It&#8217;s still early to talk about an exact release date &#8211; I won&#8217;t know that for sure until the fall, but I would expect it to be at PyCon 2013.</p>
<h3>PyRabbit</h3>
<p>I&#8217;ve blogged a bit about pyrabbit <a href="https://protocolostomy.com/2011/10/23/pyrabbit-makes-testing-and-managing-rabbitmq-easy/">before</a>: it&#8217;s a Python client for talking to RabbitMQ&#8217;s RESTful HTTP Management API. So, it&#8217;s not for building applications that do message passing with AMQP &#8212; it&#8217;d be more for monitoring, polling queue depths, etc., or if you wanted to build your own version of the browser-based management interface to RabbitMQ.</p>
<p><a href="http://github.com/bkjones/pyrabbit">Pyrabbit</a> is actually being used. Last I looked, kombu was actually using it, and if memory serves, kombu is used in Celery, so pyrabbit is probably installed on more machines than I&#8217;m aware of at this point. I also created a little command shell program called <a href="http://github.com/bkjones/bunnyq">bunnyq</a> that will let you poke at RabbitMQ remotely without having to write any code. You can create &amp; destroy most resources, fire off a message, retrieve messages, etc. It&#8217;s rudimentary, but it&#8217;s fine for quick, simple tests or to validate your understanding of the system given certain binding types, etc.</p>
<p>I have a branch wherein I port the unit tests for Pyrabbit to use a bit of a different approach, but I also need to flesh out more parts of the API and test it on more versions of RabbitMQ. If you use Pyrabbit, you should know that I also accept pull requests if they come with tests.</p>
<h3>Stealth Mode</h3>
<p>Well, &#8216;stealth&#8217; is a strong word. I actually don&#8217;t believe much in stealth mode, so if you want to know just ask me in person. Anyway, between 2008 and 2012 I&#8217;ve been involved in startups (both bought out, by the way! East Coast FTW!) that were very product driven and very focused on execution. I was lucky enough to answer directly to the CEO of one of those companies (AddThis) and directly to the CTO of the other (myYearbook, now meetme.com), which gave me a lot of access and insight into the mechanics, process, and thinking behind how a product actually comes to be. It turns out I really love certain aspects of it that aren&#8217;t even necessarily technical. I also really find the execution phase really exciting, and the rollout phase really almost overwhelmingly exciting.</p>
<p>I&#8217;ve found myself now with an idea that is really small and simple, but just won&#8217;t go away. It&#8217;s kind of gnawing at me, and the more I think about it, the more I think that, given what I&#8217;ve learned about product development, business-side product metrics, transforming some stories into an execution plan, etc., on top of my experience with software development, architecting for scalability, cloud services, tools/technologies for building distributed systems, etc., I could actually do this. It&#8217;s small and simple enough for me to get a prototype working on my own, and awesome enough to be an actual, viable product. So I&#8217;m doing it. I&#8217;m doing it too slowly, but I&#8217;m doing it.</p>
<p>By the way, the one thing I completely suck at is front end design/development. I can do it, but if I could bring on a technical co-founder of my own choosing, that person would be a front end developer who has pretty solid design chops. If you know someone, or are someone, get in touch &#8211; I&#8217;m @bkjones on Twitter, and bkjones at gmail. I&#8217;m jonesy on freenode. I&#8217;m not hard to find <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h3>In and Out of Love w/ NoSQL</h3>
<p>I&#8217;ve recently added Riak to my toolbelt, next to CouchDB, MongoDB, and Redis (primarily). I was originally thinking that Riak would be a good fit for a project I&#8217;m working on, but have grown more uncomfortable with that notion as time has passed. The fact of the matter is that my data has relationships, and it turns out that relational databases are actually a really good fit in terms of the built-in feature set. The only place they really stink is on the operations side, but it also turns out that I have, like, several years of experience in doing that! Where I finally lost patience with NoSQL for this project was this huge contradiction that I never hear anyone ever talk about. You know the one &#8212; the one where the NoSQL crowd screams about how flexible everything is and how it really fits in with the &#8220;agile&#8221; mindset, and then in another doc in the same wiki strongly drives home the message that if you aren&#8217;t 100% sure what the needs of your app are, you should really make sure you have a grasp on that up front.</p>
<p>Uhh, excuse me, but if I&#8217;m iterating quickly on an app, testing in production, iterating on what works, failing fast, and designing in the direction of, and in direct response to, my customers, HOW THE HELL DO I KNOW WHAT MY APP&#8217;S NEEDS ARE?</p>
<p>So, what I&#8217;m starting with is what I know for sure: my data has relationships. I&#8217;m experienced enough with NoSQL solutions to understand my options for modeling them &amp; enforcing the relationships, but when the relational aspect of the data is pretty much always staring you in the face and isn&#8217;t limited to a small subset of operations that rely on the relationships, it seems like a no-brainer to just use the relational database and spend my time writing code to implement actual features. If I find some aspect of the data that can benefit from a NoSQL solution later, well, then I&#8217;ll use it later!</p>
<h3>Unit Testing Patterns</h3>
<p>Most who know me know I&#8217;m kind of &#8220;into&#8221; unit testing. It&#8217;s almost like a craft unto itself, and one that I rather enjoy. I recently started a new job at AWeber Communications, where I&#8217;m working on a next-generation awesome platform to the stars 2.0 ++, and it&#8217;s all agile, TDD, kanban, and all that. It&#8217;s pretty cool. What I found in the unit tests they had when I got there were two main things:</p>
<p>First, the project used bare asserts, and used dingus in &#8220;mock it all!&#8221; mode. Combined, this led to tests that were mostly effective, but not very communicative in the event of failure, and they were somewhat difficult to reason about when you read them.</p>
<p>Second, they had a pretty cool pattern for structuring and naming that gave *running* the tests and viewing the output a more behavioral feel to them that I thought was pretty cool, and looked vaguely familiar. Later I realized it was familiar because it was similar to the very early &#8220;Introducing Behavioral Driven Development&#8221; post I saw a long time ago but never did anything with. If memory serves, that early introduction did not introduce a BDD framework like the ones popping up all over github over the past few years. It mostly relied on naming to relay the meaning, and used standard tools &#8220;behind the curtain&#8221;, and it was pretty effective.</p>
<p>So long story short, those tests have mostly been ported to use the mock module, and inherit from unittest2.TestCase (so, no more bare asserts). The failure output is much more useful, and I think the pattern that&#8217;s evolving around the tests now is unfinished but starting to look pretty cool! In the process, I also created a repository for unittest helpers that currently only contains a context manager that you feed a list of things to patch, and it&#8217;ll automatically patch and then unpatch things after the code under test is run. It has helped me start to think about building tests in a more consistent fashion, which means reading them is more predictable too, and hopefully we spend less time debugging them and less time introducing new developers to how they work.</p>The post <a href="https://protocolostomy.com/2012/08/05/what-ive-been-up-to/">What I’ve Been Up To</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></content:encoded>
					
					<wfw:commentRss>https://protocolostomy.com/2012/08/05/what-ive-been-up-to/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">995</post-id>	</item>
		<item>
		<title>PyCon Talk Proposals: All You Need to Know And More</title>
		<link>https://protocolostomy.com/2012/08/05/pycon-talk-proposals-all-you-need-to-know-and-more/</link>
					<comments>https://protocolostomy.com/2012/08/05/pycon-talk-proposals-all-you-need-to-know-and-more/#respond</comments>
		
		<dc:creator><![CDATA[bkjones]]></dc:creator>
		<pubDate>Mon, 06 Aug 2012 01:17:07 +0000</pubDate>
				<category><![CDATA[Big Ideas]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Technology]]></category>
		<guid isPermaLink="false">http://protocolostomy.com/?p=998</guid>

					<description><![CDATA[<p>Writing a talk proposal needn’t be a stressful undertaking. There are two huge factors that seem to stress people out the most about submitting a proposal, and we’re going to obliterate those right now, so here they are: It’s not always obvious how a particular section of a proposal is evaluated, so it’s not always...</p>
The post <a href="https://protocolostomy.com/2012/08/05/pycon-talk-proposals-all-you-need-to-know-and-more/">PyCon Talk Proposals: All You Need to Know And More</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></description>
										<content:encoded><![CDATA[<p>Writing a talk proposal needn’t be a stressful undertaking. There are two huge factors that seem to stress people out the most about submitting a proposal, and we’re going to obliterate those right now, so here they are:</p>
<ol>
<li>It’s not always obvious how a particular section of a proposal is evaluated, so it’s not always clear how much/little should be in a given section, how detailed/not detailed it should be, etc.</li>
<li>The evaluation and selection process is a mystery.</li>
</ol>
<h3>
What Do I Put Here?</h3>
<p>Don’t fret. Here, in detail, are all of the parts of the proposal submission form, and some insight into what’s expected to be there, and how it’s used.</p>
<h4>Title</h4>
<p>Pick your title with care. While the title may not be cause for the Program Committee to throw out your proposal, you should consider the marketing aspect of speaking at a conference. For example, there are plenty of conference-goers who, in a mad dash to figure out the talk they’ll attend next, will simply skip a title that requires manual parsing on their part.</p>
<p>So, a couple of DOs and DON’Ts:</p>
<ul>
<li>
<h4>DOs</h4>
<ul>
<li>DO insure that your title targets the appropriate audience for your talk</li>
<li>DO keep the title as short and simple as possible</li>
<li>DO insure that the title accurately reflects what the talk is about</li>
</ul>
</li>
<li>
<h4>DON’Ts</h4>
<ul>
<li>DON’T have a vague title</li>
<li>DON’T omit key words that are crucial to understanding who the talk is for</li>
<li>DON’T create a title that’s too long or wordy</li>
</ul>
</li>
</ul>
<p>So, in short, keep the title short and clear. There’s no hard and fast rule regarding length, of course, but consider how many best-selling book titles have ever had more than, say, 7 words? I’m sure it’s happened, but it’s probably more the exception than the rule. If you feel you need a very long title in order to meet the goals of the title, describe your proposal by some friends or coworkers, and when they say “So&#8230; how to do ‘x’ with ‘y’, basically, right?”, that’s actually your title. Be gracious and thank them.</p>
<p>Within your concise title, you should absolutely make certain to target your audience, if your audience is a very specific subset of the overall attendee list. For example, if you’re writing a proposal about testing Django applications, and the whole talk revolves around Django’s built-in testing facilities, your title pretty much has to say “Django” in it, for two reasons:</p>
<ol>
<li>If I’m a Django user, I really want to make sure I’ve discovered all of the Django talks before I decide what I’m doing, and if your title doesn’t say “Django” in it, lots of other ones do. A reasonable person will expect to see a key word like that in the title.</li>
<li>If I’m *not* a Django user and show up to your “Unit Testing Web Applications” talk, only to discover 10 minutes into a 25-minute talk that I’ll get nothing out of it, I’m going to really be peeved.</li>
</ol>
<p>Finally, unless you totally and completely know what you’re doing, DO NOT use a clever title using a play on words and not a single technology-related word in the whole thing. There are several issues with doing this, but probably the most obvious ones are:</p>
<ol>
<li>You’re not your audience: just because you get the reference and think it’s a total no-brainer, it’s almost guaranteed that 95% of the attendees will not get it when quickly glancing over a list of 100 talk titles.</li>
<li>You’re basically forcing the reader to read the abstract to see if they’ve even heard of the technology your talk is about. Don’t waste their time!</li>
</ol>
<h4>
Category</h4>
<p>The ‘Category’ form element is a drop-down list of high-level categories like ‘Concurrency’, ‘Mobile’, and ‘Gaming’. There are lots of categories. You may pick one. So if you have an awesome talk about how you use a standard WSGI app in a distributed deployment to get better numbers from your HPC system without the fancy interconnects, you might wonder whether to put your talk into the ‘HPC’ category or the ‘Web Frameworks’ category.</p>
<p>In cases such as this, it can be helpful to focus on the audience to help guide your decision. What do you think your audience would look like for this talk? Well, of course there are web framework authors and users who will absolutely be interested in the talk, but there isn’t a lot of gain for them in a talk like this, is there? I mean, what are the chances that someone in the audience has always dreamed of writing web frameworks for the HPC market? On the other hand, what are the chances that an HPC administrator, developer, or site manager would love to cut costs, ease deployment, reduce maintenance overhead, etc., of their HPC system by using a totally standard non-commercial web framework? There are probably valid arguments to be made for putting it in the ‘Web Frameworks’ category, but I can’t think of any. I’d put it in the ‘HPC’ category.</p>
<p>One more thing to consider is the other talks at the conference, or talks that could be at the conference, or talks from past conferences. Look at last year’s program. Where does your talk fit in that mix of talks? What talks would your talk have competed with? Is there a talk from last year that is similar in scope to your proposal? What category was it listed in?<br />
Audience Level</p>
<p>There’s a ton of gray area in selecting your target audience level. I’ve never liked the sort of arbitrary “Novice means less than X years experience” formulas, so I’ll do my best to lay out some rules of thumb, but ultimately, what you consider ‘Novice’, and how advanced you think your material is, is up to you. Your choices are:</p>
<ul>
<li>Novice:
<ul>
<li>Has used but not created a decorator and context manager.</li>
<li>Has possibly never used anything in the itertools, collections, operator, and/or functools modules</li>
<li>Has used but never had any issues with the datetime, email, or urllib modules.</li>
<li>Has seen list comprehensions, but takes some time to properly parse them</li>
</ul>
</li>
<li>Intermediate:
<ul>
<li>Has created at least a decorator, and possibly a context manager.</li>
<li>Has recently had use for the operator module (and used it) and has accepted itertools as their savior.</li>
<li>Has had a big problem with at least one of: datetime, email, or urllib.</li>
<li>There’s only a slight chance they’ve ever created or knowingly made use of metaclasses.</li>
<li>Has potentially never had to use the socket module directly for anything other than hostname lookups.</li>
<li>Can write a (non-nested) list comprehension, and does so somewhat regularly.</li>
</ul>
</li>
<li>Advanced:
<ul>
<li>Has created both a decorator and context manager using both functions and classes.</li>
<li>Has written their own daemonization module using Stevens as their reference.</li>
<li>Has been required to understand the implications of metaclasses and/or abstract base classes in a system.</li>
<li>May be philosophically opposed to list comprehensions, metaclasses, and abstract base classes</li>
<li>Has subclassed at least one of the built-in container types</li>
</ul>
</li>
</ul>
<p>Still not sure where your talk belongs? Well, hopefully you’re torn between only two of the user categories, in which case, I say “aim high”, for a few reasons:</p>
<ol>
<li>It’s generally easier to trim a talk to target a less experienced audience than you were expecting than to grow to accommodate a more experienced audience than you were expecting.</li>
<li>Speaking purely anecdotally and with zero statistics, and from memory, there are lots more complaints about talks being more advanced than their chosen audience level than the reverse.</li>
</ol>
<p>The Program Committee uses the category to insure that, within any given topic space, there’s a good selection of talks for all levels of attendees. In cases where a talk might otherwise be tossed for being too similar to (and not better than) another, targeting a different audience level could potentially save the day.</p>
<h4>Extreme?</h4>
<p>Talk slots are relatively short. Your idea for a talk is awesome, but way too long. What if you could give that talk to an audience that doesn’t need the whole 15-minute introductory part of the talk? What if, when your time started ticking down, you immediately jumped into the meat of the topic? That’s what Extreme talks are for.</p>
<p>I’d recommend checking the ‘Extreme’ box on the submission form only if your talk *could potentially* be an Extreme talk. Why? Two reasons:</p>
<ol>
<li>The number of Extreme slots is limited, and</li>
<li>If your talk is not accepted into an ‘Extreme’ slot, it may still be accepted as a regular talk.</li>
</ol>
<h4>Duration</h4>
<p>There are 30-minute or 45-minute slots, or you can choose ‘No Preference’. I recommend modeling your proposal around the notion that it could be in either time slot: your ability to be flexible helps the Program Committee to be flexible as well. If your talk competes with another in the process and the only difference of any use that anyone can find is that your talk has a hard, 45-minute slot requirement, you probably have a good chance of losing that battle.</p>
<p>If you’d like to have a 45-minute slot, then it might help you out to build your outline for a 30-minute talk first, and then go back and add bullet points to it that are clearly marked “(If 45min slot)” or something. Alternatively, you can create the outline based on a 45-minute slot, and just use the ‘Additional Notes’ section of the form to explain how you’d alter the talk if the committee requested you do the talk in 30 minutes.</p>
<h4>Description</h4>
<p>This is the description that, if your talk is accepted, people will be reading in the conference program. It needs to:</p>
<ol>
<li>Be compelling</li>
<li>Make a promise</li>
<li>Be 400 characters or less</li>
</ol>
<p>Being compelling can seem very difficult, depending on your topic space. It might help to consider that you only need to be compelling to your target audience. So, while a talk called “Writing Unit Tests” is probably not compelling to the already-testing contingent at the conference, it might be totally compelling for those who aren’t but want to. Meanwhile, a talk called “Setting Up a local Automated TDD Environment in Python 3 With Zero External Dependencies” is probably pretty compelling to the already-testing crowd and not so compelling to those who aren’t yet writing tests.</p>
<p>Making a promise to the reader means that you’re setting an expectation in their mind that you’ll make good on some deliverable at some point in the talk. Some key phrases to use in your description to call out this promise might be “By the end of this talk, you’ll have&#8230;”, or “If you want to have a totally solid grasp of&#8230;”. The key that both of those phrases have in common is that they both imply that you’re about to tell them what they can expect to get out of the talk. It answers a question in every conference-goer’s mind when reading talk descriptions, which is “What’s in it for me?”. If you don’t answer that question in the description, it may be harder for people to guess what’s in it for them, and frankly they won’t spend a lot of time trying!</p>
<h4>Abstract</h4>
<p>The form expects a detailed description of the talk, along with an outline describing the flow of the talk. That said, it’s not expected that the talk you outline in August is precisely the same talk you deliver the following March. However, if your talk is accepted, the outline will be made public online (it will not be printed in the conference program), so you’d like to hit the outline as close as possible.</p>
<p>The abstract section will be used by the program committee to answer various questions about the talk, possibly including (but certainly not limited to):</p>
<ul>
<li>Whether the talk’s title and description actually describe the talk as detailed in the abstract. Will attendees get pretty much what they expect if they only read the title and description of the talk?</li>
<li>Whether the talk appears to target the correct audience level. If you’re targeting a novice audience, your abstract should not go into topics that are beyond that audience level.</li>
<li>Whether the scope of the talk is realistic given the time constraints. If you asked for a 30-minute slot, your abstract should not make the committee think that it would be impossible to cover all of the material even given a whole hour. It’s not uncommon to be a little off in this regard, but being really far off could be an indicator that the proposer may not have thought this through very well.</li>
<li>Whether the talk is organized and has a logical flow that incorporates any known essential, obvious topics that should be touched on.</li>
</ul>
<h4>Additional Notes</h4>
<p>This is a free-form text field where you can pretty much talk directly to the Program Committee to let them know in your own way why you think your talk is awesome, how you envision it coming off, and how you see the audience benefitting from it and finding value in attending the talk.</p>
<p>Although there are no hard requirements for this section of the submission form, you should absolutely, positively include any of the following that you can:</p>
<ul>
<li>If your talk is about a new software project, a link to the project’s homepage, repository, and anything other relevant articles, interviews, testimonials, etc., about the project.</li>
<li>Links to any online slides or videos from any presentations you’ve given previously.</li>
<li>Comments discussing how you’d handle moving from a 45-minute to 30-minute slot, or from an Extreme slot to a regular slot, etc. In general, it helps the committee to know you’ve thought about contingencies in your proposal.</li>
</ul>
<h3>Great, so&#8230; How do I do this?</h3>
<p>If you’ve never written a proposal before, and you’re not sure what you want to talk about, don’t have a crystal clear vision for a talk, have trouble narrowing the scope of your idea, and don’t know exactly where to start, I have a few ideas that might help you get the proposal creation juices flowing:</p>
<ul>
<li>Write down some bullet points in a plain text file that are titles or one-line summaries of talks you’d like to see. Forget about whether you’re even willing or able to actually produce these talks &#8211; the idea is to start moving things from your brain onto a page. When you’ve got 5-10 of these points, reflect:
<ul>
<li>Could you deliver any of these yourself?</li>
<li>Could you apply an idea contained in a point to a topic you’re more familiar with?</li>
<li>Is there a topic related to any of the points that touch on things you know well?</li>
<li>Do any of these points jog your memory and make you think of projects you’ve worked on in the past that might be a source for a talk idea?</li>
</ul>
</li>
<li>Do an informal audit of what you’ve done over the past year.
<ul>
<li>Were there problems you faced that there’s no good solution for?</li>
<li>Did you grow in some way that was really important, and could you help others to learn those lessons, and learn why those lessons are important?</li>
<li>Did you make use of a new technology?</li>
<li>Did you change how you do your job? Your development workflow? Your project lifecycle? Automation? Task management?</li>
</ul>
</li>
<li>Go through the talks on pyvideo.org. It’s such an enormous, and enormously valuable trove. You could just scan the titles and see if something comes up. If that doesn’t work, click on a few, but don’t watch the talk: skip to the Q&amp;A at the end. Buried in the Q&amp;A are always these gems that are only tangentially related, and it is not uncommon to hear a speaker respond with “&#8230;but that’s another whole talk&#8230;”. They’re sometimes right.</li>
</ul>
<p>Make it happen!</p>The post <a href="https://protocolostomy.com/2012/08/05/pycon-talk-proposals-all-you-need-to-know-and-more/">PyCon Talk Proposals: All You Need to Know And More</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></content:encoded>
					
					<wfw:commentRss>https://protocolostomy.com/2012/08/05/pycon-talk-proposals-all-you-need-to-know-and-more/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">998</post-id>	</item>
		<item>
		<title>Sending Alerts With Graphite Graphs From Nagios</title>
		<link>https://protocolostomy.com/2012/02/24/sending-alerts-with-graphite-graphs-from-nagios/</link>
					<comments>https://protocolostomy.com/2012/02/24/sending-alerts-with-graphite-graphs-from-nagios/#comments</comments>
		
		<dc:creator><![CDATA[bkjones]]></dc:creator>
		<pubDate>Fri, 24 Feb 2012 19:08:36 +0000</pubDate>
				<category><![CDATA[Hacks]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Web Services]]></category>
		<guid isPermaLink="false">http://protocolostomy.com/?p=959</guid>

					<description><![CDATA[<p>Disclaimer The way I&#8217;m doing this relies on a feature I wrote for Graphite that was only recently merged to trunk, so at time of writing that feature isn&#8217;t in a stable release. Hopefully it&#8217;ll be in 0.9.10. Until then, you can at least test this setup using Graphite&#8217;s trunk version. Oh yeah, the new...</p>
The post <a href="https://protocolostomy.com/2012/02/24/sending-alerts-with-graphite-graphs-from-nagios/">Sending Alerts With Graphite Graphs From Nagios</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></description>
										<content:encoded><![CDATA[<h2 id="SendingAlertsWithGraphiteGraphsFromNagios-DefiningContacts">Disclaimer</h2>
<p>The way I&#8217;m doing this relies on a feature I wrote for Graphite that was only recently merged to trunk, so at time of writing that feature isn&#8217;t in a stable release. Hopefully it&#8217;ll be in 0.9.10. Until then, you can at least test this setup using Graphite&#8217;s trunk version.</p>
<p>Oh yeah, the new feature is the ability to send graph images (not links) via email. I surfaced this feature in Graphite through the graph menus that pop up when you click on a graph in Graphite, but implemented it such that it&#8217;s pretty easy to call from a script (which I also wrote &#8211; you&#8217;ll see if you read the post).</p>
<p>Also, note that I assume you already know Nagios, how to install new command scripts, and all that. It&#8217;s really easy to figure this stuff out in Nagios, and it&#8217;s well-documented elsewhere, so I don&#8217;t cover anything here but the configuration of this new feature.</p>
<h2>The Idea</h2>
<p>I&#8217;m not a huge fan of Nagios, to be honest. As far as I know, nobody really is. We all just use it because it&#8217;s there, and the alternatives are either overkill, unstable, too complex, or just don&#8217;t provide much value for all the extra overhead that comes with them (whether that&#8217;s config overhead, administrative overhead, processing overhead, or whatever depends on the specific alternative you&#8217;re looking at). So&#8230; Nagios it is.</p>
<p>One thing that *is* pretty nice about Nagios is that configuration is really dead simple. Another thing is that you can do pretty much whatever you want with it, and write code in any language you want to get things done. We&#8217;ll take advantage of these two features to actually do a couple of things:</p>
<ul>
<li>Monitor a metric by polling Graphite for it directly</li>
<li>Tell Nagios to fire off a script that&#8217;ll go get the graph for the problematic metric, and send email with the graph embedded in it to the configured contacts.</li>
<li>Record that we sent the alert back in Graphite, so we can overlay those events on the corresponding metric graph and verify that alerts are going out when they should, that the outgoing alerts are hitting your phone without delay, etc.</li>
</ul>
<h2>The Candy</h2>
<p>Just to be clear, we&#8217;re going to set things up so you can get alert messages from Nagios that look like this (click to enlarge):</p>
<p><a href="https://protocolostomy.com/wp-content/uploads/2012/02/iphone-graphite.png"><img fetchpriority="high" decoding="async" data-attachment-id="961" data-permalink="https://protocolostomy.com/2012/02/24/sending-alerts-with-graphite-graphs-from-nagios/iphone-graphite/" data-orig-file="https://protocolostomy.com/wp-content/uploads/2012/02/iphone-graphite.png" data-orig-size="640,960" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="iphone-graphite" data-image-description="" data-image-caption="" data-medium-file="https://protocolostomy.com/wp-content/uploads/2012/02/iphone-graphite-200x300.png" data-large-file="https://protocolostomy.com/wp-content/uploads/2012/02/iphone-graphite.png" class="alignnone size-medium wp-image-961" title="iphone-graphite" src="https://protocolostomy.com/wp-content/uploads/2012/02/iphone-graphite-200x300.png" alt="" width="200" height="300" srcset="https://protocolostomy.com/wp-content/uploads/2012/02/iphone-graphite-200x300.png 200w, https://protocolostomy.com/wp-content/uploads/2012/02/iphone-graphite.png 640w" sizes="(max-width: 200px) 100vw, 200px" /></a></p>
<p>And you&#8217;ll also be able to track those alert events in Graphite in graphs that look like this (click to enlarge, and note the vertical lines &#8211; those are the alert events.):</p>
<p><a href="https://protocolostomy.com/wp-content/uploads/2012/02/overlay-alert-events1.png"><img decoding="async" data-attachment-id="963" data-permalink="https://protocolostomy.com/2012/02/24/sending-alerts-with-graphite-graphs-from-nagios/overlay-alert-events-2/" data-orig-file="https://protocolostomy.com/wp-content/uploads/2012/02/overlay-alert-events1.png" data-orig-size="700,400" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="overlay-alert-events" data-image-description="" data-image-caption="" data-medium-file="https://protocolostomy.com/wp-content/uploads/2012/02/overlay-alert-events1-300x171.png" data-large-file="https://protocolostomy.com/wp-content/uploads/2012/02/overlay-alert-events1.png" class="alignnone size-medium wp-image-963" title="overlay-alert-events" src="https://protocolostomy.com/wp-content/uploads/2012/02/overlay-alert-events1-300x171.png" alt="" width="300" height="171" srcset="https://protocolostomy.com/wp-content/uploads/2012/02/overlay-alert-events1-300x171.png 300w, https://protocolostomy.com/wp-content/uploads/2012/02/overlay-alert-events1.png 700w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<h2>Defining Contacts</h2>
<p>In production, it&#8217;s possible that the proper contacts and contact groups already exist. For testing (and maybe production) you might find that you want to limit who receives graphite graphs in email notifications. To test things out, I defined:</p>
<ul>
<li>A new contact template that&#8217;s configured specifically to receive the graphite graphs. Without this, no graphs.</li>
<li>A new contact that uses the template</li>
<li>A new contact group containing said contact.</li>
</ul>
<p>For testing, you can create a test contact in templates.cfg:</p>
<div>
<div>
<div>
<div id="highlighter_615404">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div title="Hint: double-click to select code">
<div><code>define contact{</code></div>
<div><code>        </code><code>name                            graphite-contact </code></div>
<div><code>        </code><code>service_notification_period     24x7            </code></div>
<div><code>        </code><code>host_notification_period        24x7 </code></div>
<div><code>        </code><code>service_notification_options    w,u,c,r,f,s </code></div>
<div><code>        </code><code>host_notification_options       d,u,r,f,s  </code></div>
<div><code>        </code><code>service_notification_commands   notify-svcgraph-by-email</code></div>
<div><code>        </code><code>host_notification_commands      notify-host-by-email</code></div>
<div><code>        </code><code>register                        </code><code>0</code></div>
<div><code>        </code><code>}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<p>You&#8217;ll notice a few things here:</p>
<ul>
<li>This is not a contact, only a template.</li>
<li>Any contact defined using this template will be notified of <strong>service</strong> issues with the command &#8216;notify-svcgraph-by-email&#8217;, which we&#8217;ll define in a moment.</li>
</ul>
<p>In contacts.cfg, you can now define an individual contact that uses the graphite-contact template we just assembled:</p>
<div>
<div>
<div>
<div id="highlighter_781276">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div title="Hint: double-click to select code">
<div><code>define contact{</code></div>
<div><code>        </code><code>contact_name    graphiteuser</code></div>
<div><code>        </code><code>use             graphite-contact </code></div>
<div><code>        </code><code>alias           Graphite User</code></div>
<div><code>        </code><code>email           someone</code><code>@example</code><code>.com </code></div>
<div><code>        </code><code>}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<p>Of course, you&#8217;ll want to change the &#8217;email&#8217; attribute here, even for testing.</p>
<p>Once done, you also want to have a contact group set up that contains this new &#8216;graphiteuser&#8217;, so that you can add users to the group to expand the testing, or evolve things into production. This is also done in contacts.cfg:</p>
<div>
<div>
<div>
<div id="highlighter_342288">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div title="Hint: double-click to select code">
<div><code>define contactgroup{</code></div>
<div><code>        </code><code>contactgroup_name       graphiteadmins</code></div>
<div><code>        </code><code>alias                   Graphite Administrators</code></div>
<div><code>        </code><code>members                 graphiteuser</code></div>
<div><code>        </code><code>}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<h2 id="SendingAlertsWithGraphiteGraphsFromNagios-DefiningaService">Defining a Service</h2>
<p>Also for testing, you can set up a test service, necessary in this case to bypass default settings that seek to <strong>not</strong> bombard contacts by sending an email for every single aberrant check. Since the end result of this test is to see an email, we want to get an email for every check where the values are in any way out of bounds. In templates.cfg put this:</p>
<div>
<div>
<div>
<div id="highlighter_429252">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div title="Hint: double-click to select code">
<div><code>define service{</code></div>
<div><code>    </code><code>name                        test-service</code></div>
<div><code>    </code><code>use                         generic-service</code></div>
<div><code>    </code><code>passive_checks_enabled      </code><code>0</code></div>
<div><code>    </code><code>contact_groups              graphiteadmins</code></div>
<div><code>    </code><code>check_interval              </code><code>20</code></div>
<div><code>    </code><code>retry_interval              </code><code>2</code></div>
<div><code>    </code><code>notification_options        w,u,c,r,f</code></div>
<div><code>    </code><code>notification_interval       </code><code>30</code></div>
<div><code>    </code><code>first_notification_delay    </code><code>0</code></div>
<div><code>    </code><code>flap_detection_enabled      </code><code>1</code></div>
<div><code>    </code><code>max_check_attempts          </code><code>2</code></div>
<div><code>    </code><code>register                    </code><code>0</code></div>
<div><code>    </code><code>}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<p>Again, the key point here is to insure that <strong>no</strong> notifications are ever silenced, deferred, or delayed by nagios in any way, for any reason. You probably don&#8217;t want this in production. The other point is that when you set up an alert for a service that uses &#8216;test-service&#8217; in its definition, the alerts will go to our previously defined &#8216;graphiteadmins&#8217;.</p>
<p>To make use of this service, I&#8217;ve defined a service in &#8216;localhost.cfg&#8217; that will require further explanation, but first let&#8217;s just look at the definition:</p>
<div>
<div>
<div>
<div id="highlighter_533070">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div title="Hint: double-click to select code">
<div><code>define service{</code></div>
<div><code>        </code><code>use                             test-service </code></div>
<div><code>        </code><code>host_name                       localhost</code></div>
<div><code>        </code><code>service_description             Some Important Metric</code></div>
<div><code>        </code><code>_GRAPHURL           </code><code>"<a href="http://graphite01.scs.myyearbook.com/render?width=800&amp;from=-1hours&amp;until=now&amp;target=derivative(myyearbook.mobile.MobileBugReports.ConnectException.Reports.bug.crashreports)">http://graphite.example.com/render?width=800&amp;from=-1hours&amp;until=now&amp;target=graphite.path.to.target"</a></code></div>
<div><code>        </code><code>check_command                   check_graphite_data!</code><code>24</code><code>!</code><code>36</code></div>
<div><code>        </code><code>notifications_enabled           </code><code>1</code></div>
<div><code>        </code><code>}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<p>There are two new things we need to understand when looking at this definition:</p>
<ul>
<li>What is &#8216;check_graphite_data&#8217;?</li>
<li>What is &#8216;_GRAPHURL&#8217;?</li>
</ul>
<p>These questions are answered in the following section.</p>
<p>In addition, you should know that the value for _GRAPHURL is intended to come straight from the Graphite dashboard. Go to your dashboard, pick a graph of a single metric, grab the URL for the graph, and paste it in (and double-quote it).</p>
<h2 id="SendingAlertsWithGraphiteGraphsFromNagios-DefiningthecheckgraphitedataCommand">Defining the &#8216;check_graphite_data&#8217; Command</h2>
<p>This command relies on a small script written by the folks at Etsy, which can be found on github: <a href="https://github.com/etsy/nagios_tools/blob/master/check_graphite_data" rel="nofollow">https://github.com/etsy/nagios_tools/blob/master/check_graphite_data</a></p>
<p>Here&#8217;s the commands.cfg definition for the command:</p>
<div>
<div>
<div>
<div id="highlighter_773344">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div title="Hint: double-click to select code">
<div><code># </code><code>'check_graphite_data'</code> <code>command definition</code></div>
<div><code>define command{</code></div>
<div><code>        </code><code>command_name    check_graphite_data</code></div>
<div><code>        </code><code>command_line    $USER1$/check_graphite_data -u $_SERVICEGRAPHURL$ -w $ARG1$ -c $ARG2$</code></div>
<div><code>        </code><code>}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<p>The &#8216;command_line&#8217; attribute calls the check_graphite_data script we got on github earlier. The &#8216;-u&#8217; flag is a URL, and this is actually using the custom object attribute &#8216;_GRAPHURL&#8217; from our service definition. You can see more about custom object variables here: <a href="http://nagios.sourceforge.net/docs/3_0/customobjectvars.html" rel="nofollow">http://nagios.sourceforge.net/docs/3_0/customobjectvars.html</a> &#8211; the short story is that, since we defined _GRAPHURL in a service definition, it gets prepended with &#8216;SERVICE&#8217;, and the underscore in &#8216;_GRAPHURL&#8217; moves to the front, giving you &#8216;$_SERVICEGRAPHURL&#8217;. More on how that works at the link provided.</p>
<p>The &#8216;-w&#8217; and &#8216;-c&#8217; flags to check_graphte_data are &#8216;warning&#8217; and &#8216;critical&#8217; thresholds, respectively, and they correlate to the positions of the service definition&#8217;s &#8216;check_command&#8217; arguments (so, check_graphite_data!24!36 maps to &#8216;check_graphite_data -u &lt;url&gt; -w 24 -c 36&#8217;)</p>
<h2 id="SendingAlertsWithGraphiteGraphsFromNagios-Definingthenotify-svcgraph-by-emailCommand">Defining the &#8216;notify-svcgraph-by-email&#8217; Command</h2>
<p>This command relies on a script that I wrote in Python called &#8216;sendgraph.py&#8217;, which also lives in github: <a href="https://gist.github.com/1902478">https://gist.github.com/1902478</a></p>
<p>The script does two things:</p>
<ul>
<li>It emails the graph that corresponds to the metric being checked by Nagios, and</li>
<li>It pings back to graphite to record the alert itself as an event, so you can define a graph for, say, &#8216;Apache Load&#8217;, and if you use this script to alert on that metric, you can also overlay the alert events on top of the &#8216;Apache Load&#8217; graph, and vet that alerts are going out when you expect. It&#8217;s also a good test to see that you&#8217;re actually getting the alerts this script tries to send, and that they&#8217;re not being dropped or seriously delayed.</li>
</ul>
<p>To make use of the script in nagios, lets define the command that actually sends the alert:</p>
<div>
<div>
<div>
<div id="highlighter_982380">
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<div title="Hint: double-click to select code">
<div><code>define command{</code></div>
<div><code>    </code><code>command_name    notify-svcgraph-by-email</code></div>
<div><code>    </code><code>command_line    /path/to/sendgraph.py -u </code><code>"$_SERVICEGRAPHURL$"</code> <code>-t $CONTACTEMAIL$ -n </code><code>"$SERVICEDESC$"</code> <code>-s $SERVICESTATE$</code></div>
<div><code>    </code><code>}</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<p>A couple of quick notes:</p>
<ul>
<li>Notice that you need to double-quote any variables in the &#8216;command_line&#8217; that might contain spaces.</li>
<li>For a definition of the command line flags, see sendgraph.py&#8217;s &#8211;help output.</li>
<li>Just to close the loop, note that notify-svcgraph-by-email is the &#8216;service_notification_commands&#8217; value in our initial contact template (the very first listing in this post)</li>
</ul>
<h2 id="SendingAlertsWithGraphiteGraphsFromNagios-FireItUp">Fire It Up</h2>
<p>Fire up your Nagios daemon to take it for a spin. For testing, make sure you set the check_graphite_data thresholds to numbers that are pretty much guaranteed to trigger an alert when Graphite is polled. Hope this helps! If you have questions, first make sure you&#8217;re using Graphite&#8217;s &#8216;trunk&#8217; branch, and not 0.9.9, and then give me a shout in the comments.</p>The post <a href="https://protocolostomy.com/2012/02/24/sending-alerts-with-graphite-graphs-from-nagios/">Sending Alerts With Graphite Graphs From Nagios</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></content:encoded>
					
					<wfw:commentRss>https://protocolostomy.com/2012/02/24/sending-alerts-with-graphite-graphs-from-nagios/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">959</post-id>	</item>
		<item>
		<title>The Python User Group in Princeton (PUG-IP): 6 months in</title>
		<link>https://protocolostomy.com/2011/11/02/the-python-user-group-in-princeton-pug-ip-6-months-in/</link>
					<comments>https://protocolostomy.com/2011/11/02/the-python-user-group-in-princeton-pug-ip-6-months-in/#comments</comments>
		
		<dc:creator><![CDATA[bkjones]]></dc:creator>
		<pubDate>Thu, 03 Nov 2011 04:08:40 +0000</pubDate>
				<category><![CDATA[Big Ideas]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Sysadmin]]></category>
		<category><![CDATA[Technology]]></category>
		<guid isPermaLink="false">http://protocolostomy.com/?p=956</guid>

					<description><![CDATA[<p>In May, 2011, I started putting out feelers on Twitter and elsewhere to see if there might be some interest in having a Python user group that was not in Philadelphia or New York City. A single tweet resulted in 5 positive responses, which I took as a success, given the time-sensitivity of Twitter, my...</p>
The post <a href="https://protocolostomy.com/2011/11/02/the-python-user-group-in-princeton-pug-ip-6-months-in/">The Python User Group in Princeton (PUG-IP): 6 months in</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></description>
										<content:encoded><![CDATA[<p>In May, 2011, I started putting out feelers on Twitter and elsewhere to see if there might be some interest in having a Python user group that was not in Philadelphia or New York City. A single tweet resulted in 5 positive responses, which I took as a success, given the time-sensitivity of Twitter, my &#8220;reach&#8221; on Twitter (which I assume is far smaller than what might be the entire target audience for that tweet), etc.</p>
<p>Happy with the responses I received, I still wanted to take a baby step in getting the group started. Rather than set up a web site that I&#8217;d then have to maintain, a mailing list server, etc., I went to the cloud. I started a <a href="http://meetup.com/pug-ip">group on meetup.com</a>, and started looking for places to hold our first meeting.</p>
<h3>Meetup.com</h3>
<p>Meetup.com, I&#8217;m convinced, gives you an enormous value if you&#8217;re looking to start a user group Right Now, Today<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2122.png" alt="™" class="wp-smiley" style="height: 1em; max-height: 1em;" />. For $12/mo., you get a place where you can announce future meetups, hold discussions, collect RSVPs so you have a head count for food or space or whatever, and vendors can also easily jump in to provide sponsorship or &#8216;perks&#8217; in the form of discounts on services to user group members and the like. It&#8217;s a lot for a little, and it&#8217;s worked well enough. If we had to stick with it for another year, I&#8217;d have no real issue with that.</p>
<h3>Google Groups</h3>
<p>I set up a mailing list using Google Groups about 2-3 months ago now. I only waited so long because I thought meetup.com&#8217;s discussion forum might work for a while. After a few meetings, though, I noticed that there were always about five more people in attendance than had RSVP&#8217;d on meetup.com. Some people just aren&#8217;t going to be bothered with having yet another account on yet another web site I guess. If that&#8217;s the case, then I have two choices (maybe more, but these jumped to mind): force the issue by constantly trumpeting meetup.com&#8217;s service, or go where everyone already was. Most people have a Google account, and understand its services. Also, since the group is made up of technical people, they mostly like the passive nature of a mailing list as opposed to web forums.</p>
<p>If you&#8217;re setting up a group, I&#8217;d say that setting up a group on meetup.com and simultaneously setting up a Google group mailing list is the way to go if you want to get a fairly complete set of services for very little money and about an hour&#8217;s worth of time.</p>
<h3>Meeting Space</h3>
<p>Meeting space can come from a lot of different places, but I had a bit of trouble settling on a place at first. Princeton University is an awesome place and has a ton of fantastic places to meet with people, but if you&#8217;re not living on campus (almost no students are group members, btw), parking can be a bit troublesome, and Princeton University is famous for having little or no signage, and that includes building names, so finding where to go even if you did find parking can be problematic. So, so far, the University is out.</p>
<p>The only sponsor I had that was willing to provide space was my employer, but we&#8217;re nowhere near Princeton, and don&#8217;t really have the space. Getting a sponsor for space can be a bit difficult when your group doesn&#8217;t exist yet, in part because none of them have engaged with you or your group until the first meeting, when the attendees, who all work for potential sponsors, show up.</p>
<p>I started looking at the web site for the <a href="http://www.princeton.lib.nj.us/">Princeton Public Library</a>. I&#8217;ve been involved in the local Linux user group for several years, and they use free meeting space made available by the public library in Lawrenceville, which borders Princeton. I wondered if the Princeton Public Library did this as well, but they don&#8217;t, actually. In fact, meeting space at that location can get pretty expensive, since they charge for the space and A/V equipment like projectors and stuff separately (or they did when I started the group &#8211; I believe it&#8217;s still the case).</p>
<p>I believe I tweeted my disappointment about the cost of meeting at the Princeton Public Library, and did a callout on Twitter for space sponsors and other ideas about meeting space in or near Princeton. The Princeton Public Library got in touch through their @PrincetonPL Twitter account, and we were able to work out a really awesome deal where they became a sponsor, and agreed to host our group for 6 months, free of charge. Awesome!</p>
<p>Now, six months in, we either had to come to some other agreement with the library, or move on to a new space. After six months, it&#8217;s way easier to find space, or sponsors who might provide space, but I felt if we could find some way to continue the relationship with the library, it&#8217;d be best not to relocate the group. We wound up finding a deal that does good things for the group, the library, the local Python user community, and the evangelism of the Python language&#8230;.</p>
<h3>Knowledge for Space</h3>
<p>Our group got a few volunteers together to commit to providing a 5-week training course to the public, held at the Princeton Public Library. Adding public offerings like this adds value to the library, attracts potential new members (they&#8217;re a member-supported library, not a state/municipality-funded one), etc. In exchange for providing this service to the library, the library provides us with free meeting space, including the A/V equipment.</p>
<p>If you don&#8217;t happen to have a public library that offers courses, seminars, etc., to the general public, you might be able to cut a similar deal with a local community college, or even high school. If you know of a corporation locally that uses Python or some other technology the group can speak or train people in, you might be able to trade training for meeting space in their offices. Training is a valued perk to the employees of most corporations.</p>
<h3>How To Get Talks (or &#8220;How we stopped caring about getting talks&#8221;)</h3>
<p>Whether you&#8217;re running a publishing outfit, a training event, or user group, getting people to deliver content is a challenge. Some people don&#8217;t think they have any business talking to what they perceive as a roomful of geniuses about anything. Some just aren&#8217;t comfortable talking in front of audiences, but are otherwise convinced of their own genius. Our group is trying to attack this issue in various ways, and so far it seems to be working well enough, though more ideas are welcome!</p>
<p>Basically, the group isn&#8217;t necessarily locked into traditions like &#8220;Thou shalt provide a speaker, who shalt bequeath upon our many wisdom of the ages&#8221;. Once you&#8217;ve decided as a group that having cookie-cutter meetings isn&#8217;t necessary, you start to think of all sorts of things you could all be doing together.</p>
<p>Below are some ideas, some in the works, some in planning, that I hope help other would-be group starters to get the ball rolling, and keep it in motion!</p>
<h3>Projects For the Group, By the Group</h3>
<p>Some members of PUG-IP are working together on building the pugip.org website, which is housed in a GitHub repository under the <a href="https://github.com/pugip">&#8216;pugip&#8217; GitHub organization</a>. This one project will inevitably result in all kinds of home-grown presentations &amp; events within the group. As new ideas come up and new features are implemented, people will give lightning talks about their implementation, or we&#8217;ll do a group peer review of the code, or we&#8217;ll have speakers give talks about third-party technologies we might use (so, we might have two speakers each give a 30-minute talk about two different NoSQL solutions, for example. We&#8217;ve already had a great overview of about 10 different Python micro-frameworks), etc.</p>
<p>We may also decide to break up into pairs, and then sprint together on a set of features, or a particularly large feature, or something like that.</p>
<p>As of now, we&#8217;ve made enough decisions as a group to get the ball rolling. If there&#8217;s any interest I can blog about the setup that allows the group to easily share, review, and test code, provide live demos of their work, etc. The tl;dr version is we use GitHub and free heroku accounts, but new ideas come into play all the time. Just today I was wondering if we could, as a group, make use of the cloud9 IDE (http://cloud9ide.com).</p>
<p>The website is a great idea, but other group projects are likely to come up.</p>
<h3>Community Outreach</h3>
<p>PUG-IPs first official community outreach project will be the training we provide through the Princeton Public library. A few of us will collaborate on delivering the training, but the rest of the group will be involved in providing feedback on various aspects of the material, etc., so it&#8217;s a &#8216;whole group&#8217; project, really. On top of increasing interactivity among the group members, outreach is also a great way to grow and diversify the group, and perhaps gain sponsorships as well!</p>
<p>There&#8217;s another area group called <a href="http://lugip.org">LUG-IP</a> (a Linux user group) that also does some community outreach through a hardware SIG (special interest group), certification training sessions, and participating in local computing events and conferences. I&#8217;d like to see PUG-IP do this, too, maybe in collaboration with the LUG (they&#8217;re a good and passionate group of technologists).</p>
<p>Community outreach can also mean teaming up with various other technology groups, and one event I&#8217;m really looking forward to is a RedSnake meeting to be held next February. A RedSnake meeting is a combined meeting between <a href="http://www.meetup.com/phillypug/">PhillyPUG</a> (the Philadelphia Python User Group) and <a href="http://phillyrb.org/">Philly.rb</a> (the Philadelphia Ruby Group). As a member of PhillyPUG I participated in last year&#8217;s RedSnake meeting, and it was a fantastic success. Probably 70+ people in attendance (<a href="http://twitpic.com/3xv2fi">here&#8217;s a pic</a> at the end &#8211; some had already left by the time someone snapped this), and perhaps 10 or so lightning talks given by members of both organizations. We tried to do a &#8216;matching&#8217; talk agenda at the meeting, so if someone on the Ruby side did a testing talk, we followed that with a Python testing talk, etc. It was a ton of fun, and the audience was amazing.</p>
<h3>Socials</h3>
<p>Socials don&#8217;t have to be dedicated events, per se. For example, PUG-IP has a sort of mini-social after every single meetup. We&#8217;re lucky to have our meetings located about a block away from a brewpub, so after each meeting, perhaps half of us make it over for a couple of beers and some great conversations. After a few of these socials, I started noticing that more talk proposals started to spring up.</p>
<p>Of course, socials can also be dedicated events. Maybe some day PUG-IP will&#8230;. I dunno&#8230; go bowling? Or maybe we&#8217;ll go as a group to see the next big geeky movie that comes out. Maybe we&#8217;ll have some kind of all-inclusive, bring-the-kids BBQ next summer. Who knows?</p>
<p>As a sort of sideshow event to the main LUG meetings, LUG-IP has a regularly-scheduled <a href="http://lugip.org/node/326">&#8216;coffee klatch&#8217;</a>. Some of the members meet up one Sunday per month at (if memory serves) 8-11AM at a local Panera for coffee, pastries, and geekery. It&#8217;s completely informal, but it&#8217;s a good time.</p>
<h3>Why Not Having Talks Will Help You Get Talks</h3>
<p>I have a theory that is perhaps half-proven through my experiences with technology user groups: increasing engagement among and between the members of the group in a way that doesn&#8217;t shine a huge floodlight on a single individual (like a talk would) eventually breaks down whatever fears or resistance there is to proposing and giving a talk. Sometimes it&#8217;s just a comfort level thing, and working on projects, or having a beer, or sprinting on code, etc. &#8212; together &#8212; turns a &#8220;talking in front of strangers&#8221; experience into more of a &#8220;sharing with my buddies&#8221; one.</p>
<p>I hope that&#8217;s true, anyway. It seems to be. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h3>Thanks For Reading</h3>
<p>I hope someone finds this useful. It&#8217;s early on in the life of PUG-IP, but I thought it would be valuable to get these ideas out into the ether early and often before they slip from my brain. Good luck with your groups!</p>The post <a href="https://protocolostomy.com/2011/11/02/the-python-user-group-in-princeton-pug-ip-6-months-in/">The Python User Group in Princeton (PUG-IP): 6 months in</a> first appeared on <a href="https://protocolostomy.com">Musings of an Anonymous Geek</a>.]]></content:encoded>
					
					<wfw:commentRss>https://protocolostomy.com/2011/11/02/the-python-user-group-in-princeton-pug-ip-6-months-in/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">956</post-id>	</item>
	</channel>
</rss>
