mozilla/datazilla_client — pull request #2 by carljm (2012-07-03 02:04:20+00:00)
Title: Correct docstring location/format, fix mutable-default-argument bugs.

Moved the docstrings below the class/function definition, which is the more typical location (and allows them to be found and used by Python auto-documentation tools, the online shell help() function, etc.) Also formatted them in the standard way per PEP 257 (http://www.python.org/dev/peps/pep-0257/).

Also fixed a few cases where default arguments were used in a way that would cause a subtle bug. Default arguments are evaluated at function-definition time, not function-execution time, so for instance if the default value for `test_date` is `int(time.time())`, that will be evaluated exactly once when the module is first imported, not each time a `DatazillaRequest` is created. This could be a problem in a long-running process that repeatedly creates and sends `DatazillaRequest`s.

Similarly, but even more subtly, if `[]` or `{}` (or any mutable object) is used as a default argument for a function, that creates exactly one instance of a list or dictionary, whose state will persist over time (and be shared across multiple instances of the function or class). This can be useful in some rare cases, but is almost never the desired result. For instance, with the default value of the optional `results` argument to the `DatazillaResult` constructor set to `{}`, if I run the following code:

```
res1 = DatazillaResult()
res1.add_testsuite("talos", ["1", "2"])
res2 = DatazillaResult()
```

The value of both `res1.results` and `res2.results` will, surprisingly enough, *both* be `{'talos': ['1', '2']}`. Even more surprisingly, both instances are actually sharing the same results dictionary, and any modification I make to one (i.e. adding more results) will instantly be reflected in the other as well! Because the empty-dictionary default argument is assigned to `self.results` in `res1.__init__`, but that assignment is just a reference, not a copy - there's still only one dictionary, and it's the same one that is also still the default value of the argument in the constructor. So when I add some data to `self.results` in `res1` with the second line, I'm actually adding it to the dictionary that is the default `results` argument for all `DatazillaResult'`s - and that will be also assigned to `self.results` for any future `DatazillaResult`s that are instantiated without an explicit `results` argument.

Anyway, sorry for the novel - but the solution is simple: avoid calling any functions or using any mutable objects as function default arguments. Instead use a sentinel no-argument-provided value (usually `None`) and replace it with the correct value inside the function.