pickler: handle object references with int dict keys

Integer dict keys causes the lexical sorting to be different
from the integer sorting, which leads to IndexErrors when the
dictionary contains references to objects.

Avoid the problem by using strings as the canonical
representation when sorting.  This ensures that a consistent
sort order is preserved internally and by the JSON backends.

Closes #54

Reported=by: Jason R. Coombs <jaraco@jaraco.com>
Signed-off-by: David Aguilar <davvid@gmail.com>
handlers: remove unused imports

Signed-off-by: David Aguilar <davvid@gmail.com>
tests: enable the handler tests

Signed-off-by: David Aguilar <davvid@gmail.com>
tests: remove dead code

Signed-off-by: David Aguilar <davvid@gmail.com>
tests: add more unit tests for custom handlers

Signed-off-by: David Aguilar <davvid@gmail.com>
tests: fixup the handler tests

Properly register the entire test suite.
We originally registered a single method only, which masked a
failure when running tests via `tests/runtests.py`.

Fix the assertions so that the NullHandler is expected on the
decoded object only.

Signed-off-by: David Aguilar <davvid@gmail.com>
_samples: misc style fixups

Signed-off-by: David Aguilar <davvid@gmail.com>
pickler: remove unused import

Signed-off-by: David Aguilar <davvid@gmail.com>
unpickler: use util.itemgetter everywhere

Signed-off-by: David Aguilar <davvid@gmail.com>
unpickler: allow references to objects with custom handlers

The pickler always adds a duplicate reference placeholder for custom
handlers because _mkref() is called twice in the flatten() code path
when objects have custom handlers.

This means we need to keep the same parallel count in the unpickler for
all "py/id" references that use custom handlers.

When the reference points to an object that has a custom handler create
a duplicate entry in the _objs reference list so that it can be
dereferenced.  This makes the unpickler symmetrical so that the
reference IDs properly align.

The classes used in the unit tests were provided by @c0indev3l in the
original issue.

Closes #55

Reported-by: @c0indev3l via github.com
Signed-off-by: David Aguilar <davvid@gmail.com>
pickler: simplify the fix for #55

9fd2884e342bc7094b2839140a4b6713daa1e877 was a little too complex
because the unpickler was dealing with the fallout of _mkref() getting
called twice in the flatten() code path for objects with custom
handlers.

The simpler solution is to not call _mkref() twice.  We only need to
call it on the original object instance; calling it on the flattened
representation was the source of the original bug.

This is a much better solution.

Closes #55

Signed-off-by: David Aguilar <davvid@gmail.com>
Add test for decimal; fails on Python 3