Kushal Das

FOSS and life. Kushal Das talks here.

Document your code: Part 3

You can read the part1 and part2.

Docstring

It is a string literal which is in the first statement of a module, class or function. It becomes the __doc__ attribute of the object. It contains an explanation of that object (can be module, class or a function) does.

def foobar(a, b):
    "Does foobar with a,b and returns some result"

You must have seen examples of docstrings when you started learning Python but may be you never paid enough attention to it. Now is a good time to start doing that. All the code you are writing will be used by someone (may be by you only) in future and docstrings will come into help. Remember the time when you use help command in the interpreter to learn more quickly?

>>> help(enumerate)

Help on class enumerate in module __builtin__:

class enumerate(object)
 |  enumerate(iterable[, start]) -> iterator for index, value of iterable
 |  
 |  Return an enumerate object.  iterable must be another object that supports
 |  iteration.  The enumerate object yields pairs containing a count (from
 |  start, which defaults to zero) and a value yielded by the iterable argument.
 |  enumerate is useful for obtaining an indexed list:
 |      (0, seq[0]), (1, seq[1]), (2, seq[2]), ...
 |  
 |  Methods defined here:
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  next(...)
 |      x.next() -> the next value, or raise StopIteration
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T

It actually shows the carefully written docstrings by the Python authors. Now put yourself in their shoes and try to imagine the developer who will be using your code in future.

We can have either one line or multiline docstring. If you have multiline docstring using “”” (triple quotes) then it is suggested that you have a blank line before the closing quotes. You should at least have the closing quotes on a new line.

We can also use the same docstring to create auto generated API in Sphinx , though that depends project to project.

Let us have a look into one method from python-fedora module

def people_by_key(self, key=u'username', search=u'*', fields=None):
        '''Return a dict of people

     :kwarg key: Key by this field. Valid values are 'id', 'username', or
    'email'. Default is 'username'
    :kwarg search: Pattern to match usernames against. Defaults to the
    '*' wildcard which matches everyone.
    :kwarg fields: Limit the data returned to a specific list of fields.
    The default is to retrieve all fields.
    Valid fields are:

    * affiliation
    * alias_enabled
    * bugzilla_email
    * certificate_serial
    * comments
    * country_code
    * creation
    * email
    * emailtoken
    * facsimile
    * gpg_keyid
    * group_roles
    * human_name
    * id
    * internal_comments
    * ircnick
    * last_seen
    * latitude
    * locale
    * longitude
    * memberships
    * old_password
    * password
    * password_changed
    * passwordtoken
    * postal_address
    * privacy
    * roles
    * ssh_key
    * status
    * status_change
    * telephone
    * timezone
    * unverified_email
    * username

    Note that for most users who access this data, many of these
    fields will be set to None due to security or privacy settings.
    :returns: a dict relating the key value to the fields.

    .. versionchanged:: 0.3.21
    Return a Bunch instead of a DictContainer
    .. versionchanged:: 0.3.26
    Fixed to return a list with both people who have signed the CLA
    and have not
    '''

Using :kwarg parametername: each of the keyword argument is documented. It uses :returns: to mark the returned object details. Here is one more example from kitchen module.

def isbytestring(obj):
    '''Determine if obj is a byte :class:`str`

    In python2 this is equivalent to isinstance(obj, str).  In python3 it
    checks whether the object is an instance of bytes or bytearray.

    :arg obj: Object to test
    :returns: True if the object is a byte :class:`str`.  Otherwise, False.

    .. versionadded:: Kitchen: 1.2.0, API kitchen.text 2.2.0
    '''
    if isinstance(obj, str):
        return True
    return False

Btw, never mix up between code comments and docstrings, you should never use double or triple quotes to write random comments inside your code. You should always use hashes (#) to make any comments inside your code. To know more about docstrings one should read PEP257.

reStructuredText

We use reStructuredText as our primary markup syntax for all documentations. It is plaintext and you can use it for your docstrings too. Go through this quick presentation to start writing reStructuredText. later you can learn about all directives.

Btw, that presentation was also written using reStructuredText, you can read the source file and use rst2s5 command to create your own presentation.

My choice of editor

If you are using vim or emacs then you can just continue using it. If you use sublime, you should also check out Restructured Text (RST) Snippets plugin.

comments powered by Disqus