fíam

(rhymes with liam)

  • Opensourcing byNotes

    Oct. 27, 2008 at 17:34:23 CET

    Since I started writing byNotes I wanted to release all the code under a free software license. After all, would you trust a service you cannot audit?

    However, since it all started as a small project in my free time (it's now about 30k sloc), the source code was all in one big repository and preparing it for release took some time. First, I needed to evaluate some SCM systems because I wanted to split the code into subprojects and I wasn't sure how good git-submodule was. Finally, after some analysis and some advice from newman on #django-hotclub, I went with git for the SCM and Redmine for bugtracking.

    Not all code is ready for release yet, but there are some subprojects inmediately available at the byNotes Source Code Repository. Let me introduce them:

    • django-bundles: Provides an easy way to create JS and CSS bundles, with optional support for compression and validation using YUI and rhino.
    • django-geocoding: Uses the Google APIs and django-geonames for geocoding and reverse geocoding.
    • django-geonames: Models for working with the geonames.org database.
    • django-storage: Application for storing user-uploaded files
    • django-dboembed: oEmbed client using the database for caching.

    wapi and django-oauthsp, have also been released and, the best news for some of you, all these apps are licensed under MIT license (wapi and django-oauthsp were under AGPL3), so you can use all this code with your closed source projects.

    There are more releases coming soon, including all the source code for byNotes as well as the source code for the iPhone client.

  • Wapi 0.2.1 and django-oauthsp 0.2 released

    Sept. 10, 2008 at 09:08:24 CEST

    I've finally managed to solve all known issues in django-oauthsp, so it's time to release 0.2. Wapi 0.2.1 is also here, fixing a small bug in the JSON formatter and updated to match a small API change in django-oauthsp.

    wapi-0.2.1.zip django-oauthsp-0.2.zip

  • Postback: Why I choose AGPLv3 for my code

    Aug. 29, 2008 at 11:25:23 CEST

    It's been a few days since I posted my decision to release all my code related to Django under the AGPLv3 license. It generated quite a few reactions I didn't expect, so let me tell you the full story.

    It all started when I needed to support, let's call it technology X - which is pretty hot right now -, in byNotes. I first searched if someone had done it and I found there was a generic and abstract Python implementation, but it needed a lot of work to be adapted to Django. So I decided to build my own solution from scratch. The same day I released the first version, I found an announcement posted the previous day from another developer who had also coded technology X support for Django. It's a pity when that happens, since one of us could have spent that time implementing technology Y. However, it's difficult to avoid those situations, so we must live with it.

    The bad thing (TM) happened a few days later, when I was chatting with a friend on freenode. I told him I've written support for technology X and it could be useful for a project he's working on. He told me about a relatively popular site - I didn't know it was built on Django - which had been supporting technology X for a few months. I checked the site and I found nothing about the source code for technology X, even when it's something potentially useful for a lot of sites.

    I don't blame them for not releasing their technology X implementation, after all they're free to do what they want with their code as long as they respect the licenses for other projects or frameworks they may rely on. However, the Django community lost something in this scenario. If relatively popular site had released their implementation of technology X, the other developer would have worked on Y while I would have worked on Z. Django would now have support for X, Y and Z, but thanks to the decision of relatively popular site to keep their implementation of X closed, we now have 2 free implementations of X. And that hurts the community, since now someone will have to spend time working on Y and Z instead of doing another things.

    Are you starting to see my point? Now, with my code released under AGPLv3 instead of BSD, any site using it would have to contribute their changes back. So, if they improve my implementation of technology X, I can spend more time working on technology Y and that benefits the Django community.

    I fail to see how this is being greedy. And if, as someone suggested, my code is so trivial, there's no problem reimplementing it. Anyway, I didn't claim my code does something extraordinary. In fact, I'm sure anyone could implement it. When I release something I've written, my intention is not rocking your world, but saving you from wasting time. If I've already written support for X, you're better working on Y instead of reinventing the wheel.

    However, I'm not totally happy with the AGPLv3, because of its viral nature. I would be fine with something like the LGPL but with the Affero clause and I'm sure I'm not alone. Id est, you may link closed source code with my software, but you must release any modifications you make to my code. However, there's no such license for now, so I have to use AGPLv3. Do you want this to change? Spread the word, I'm sure a new license by the FSF combining the LGPL with the Affero clause it's going to benefit us all.

  • Wapi 0.2 released

    Aug. 29, 2008 at 10:30:22 CEST

    I've just finished preparing the Wapi code for the 0.2 release, so you can now download it. oauthsp will be ready in a few days (probably this weekend).

  • Building a website API with Django. Part 6: Documentation

    Aug. 28, 2008 at 00:05:50 CEST

    This entry puts and end to "Building a website API with Django". I think I've covered everything you need to build a website API with Wapi, so it's now time for you to start playing with it. I hope you've enjoyed reading this series as much as I enjoyed writing it. I've finally pylinted and documented almost all the code, so Wapi 0.2 should be released in the next few hours. From now, I'll try to keep the current API and every backwards incompatible change will be documented.

    Documenting your API with Wapi

    Documenting your functions

    As we've seen on part 4 on this series, every API parameter takes an optional third argument which documents it. In addition, every function docstring is also passed to the documentation template. Furthermore, validators applied to parameters are also autodocumented. Let's see an example:

    @readonly
    @required_parameter('type', int, _('Admin division type, ranging from 1 to 4.'), validators=RangeValidator(min_value=1, max_value=4))
    @required_parameter('id', int, _('The administrative division id.'))
    def geo__admin(self, request, dct):
        """Returns information for the given administrative division type and id. Keep
        in mind that administrative divisions identificators are not guaranteed to
        be permanent, as it happens with geoname identifiers."""
    

    If you want to check how it looks when passed to the documentation, check the byNotes API documentation.

    urls.py

    You'll also need to plug your documentation view into your urls.py, but it's pretty simple:

    from wapi.documentator import ApiDocumentator
    from notes.api import BynotesApi
    
    urlpatterns = ...
    (r'^api/1.0/doc/', ApiDocumentator(api=BynotesApi()))
    

    Grouping functions into namespaces

    By default, Wapi orders your functions alphabetically. However, usually you'll want to reorder this namespaces and given them friendly names. In Wapi, you can do this using the NAMESPACES class attribute in your API class:

    class BynotesApi(object):
        NAMESPACES = ( 
            (_('User information'), 'user'),
            (_('Positions'), 'position'),
            (_('Fetching notes'), 'notes'),
            (_('Friends'), 'friends'),
            (_('Posting notes'), 'post'),
            (_('Geographic functions'), 'geo'),
        )
    

    The format of the tuples is (namespace_friendly_name, namespace_prefix).

    Example template

         {% for namespace in namespaces %}
        <div class="api-ns" id="ns-{{ namespace.short_name }}">
            <h2>{{ namespace.name }}</h2><ol>
            {% for function in namespace %}
            <li id="{{ function.name }}" class="function">
                <h3>
                    {{ function.endpoint }}.{ format }
                    {% if function.requires_login %}
                        <span class="warn">{% trans "Requires login" %}</span>
                    {% endif %}
                </h3>
                <span>{% trans "allowed methods" %}:</span>{% if function.is_read %} GET{% endif %}{% if function.is_write %} POST{%endif %}
                <p class="fdoc">{{ function.doc }}</p>
                {% if function.required_parameters %}
                    <h4>{% trans "Required parameters" %}:</h4>
                    {% for parameter in function.required_parameters %}
                        <p class="parameter">
                            <span>{{ parameter.name }} ({{ parameter.type_name }}):</span>
                            {{ parameter.doc }}
                        </p>
                        {% if parameter.doc_info %}
                            {% for name, value in parameter.doc_info %}
                                <p class="parameter-info">
                                    <span>{{ name }}:</span>
                                    {{ value }}
                                </p>
                            {% endfor %}
                        {% endif %}
                    {% endfor %}
                {% endif %}
                {% if function.optional_parameters %}
                    <h4>{% trans "Optional parameters" %}:</h4>
                    {% for parameter in function.optional_parameters %}
                        <p class="parameter">
                            <span>{{ parameter.name }} ({{ parameter.type_name }}):</span>
                            {{ parameter.doc }}
                        </p>
                        {% if parameter.has_default %}
                            <p class="parameter-info">
                                <span>{% trans "Default" %}:</span>
                                {{ parameter.default }}
                            </p>
                        {% endif %}
                        {% if parameter.doc_info %}
                            {% for name, value in parameter.doc_info %}
                                <p class="parameter-info">
                                        <span>{{ name }}:</span>
                                    {{ value }}
                                </p>
                            {% endfor %}
                        {% endif %}
                    {% endfor %}
                {% endif %}
            </li>
            {% endfor %}
            </ol>
        </div>
    {% endfor %}
    

    Current limitations

    As you may have noticed, translating function documentation is currently not supported in Wapi, since the docstring must be a bare string. Some work has been done on this, but the current solution requires modifications to makemessages, so I think it was better to leave this changes for Wapi 0.3, which will be released post Django 1.0.