* Fixes#12 - registering instance methods as listeners doesn’t allow to easily unregister them as the registry tries to find the handler with 'is' but it should use '==' to allow the python BoundMethod wrapper (which is a new instance every time instance.$methodname is accessed).
This is an alternative to #86 and was suggested by @mgedmin in #85.
There are tests to be sure this works for subclasses like Pyramid's
Registry that extend dict too.
This doesn't change the pickle format, we were storing the output of
object.__reduce__ previously.
- The bare import of '_zope_c_optimizations' prevented them from being
used.
- After enabling them via absolute imports, they would fail due to
http://bugs.python.org/issue15657.
Fixes#60.
Fixes#46.
Benchmarks show a dramatic improvement; not quite as good as the
demonstration in #46 because the implementation had to be a bit more
complex to properly handle unregistration, but still very good. Here it
is with 20,000 items already registered:
```
%time add_to_reg(reg, 1000)
CPU times: user 190 ms, sys: 19.3 ms, total: 209 ms
Wall time: 203 ms
```
Here's a profile with about 100,000 utilities registered:
```
%prun add_to_reg(reg, 1000)
80005 function calls (79005 primitive calls) in 0.713 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
1000 0.596 0.001 0.621 0.001 adapter.py:202(subscribe)
12000 0.016 0.000 0.019 0.000 interface.py:518(__hash__)
1000 0.010 0.000 0.709 0.001 registry.py:206(registerUtility)
3000/2000 0.009 0.000 0.014 0.000 interface.py:255(interfaces)
2000 0.008 0.000 0.022 0.000 adapter.py:637(changed)
1000 0.008 0.000 0.025 0.000 registry.py:498(_getUtilityProvided)
9000 0.008 0.000 0.017 0.000 {method 'get' of 'dict' objects}
1000 0.008 0.000 0.027 0.000 adapter.py:102(register)
2000 0.006 0.000 0.008 0.000 adapter.py:450(changed)
1000 0.005 0.000 0.663 0.001 registry.py:145(registerUtility)
```
I was very careful not to change the pickle at all.
zope.interface and zope.component tests have been run and both pass. (It
was necessary to account for the underlying objects changing because of
the way zope.component cleans up after tests.)
The decorator specifies the component name, so it does not have to be
passed in during registration. This in turn allows developers to define
component names once globally and use it everywhere, especially when
using ZCML where the name had to be specified a second time.