Commit Graph

732 Commits

Author SHA1 Message Date
Jason Madden 10eadd6305
Let interface 'subclasses' override __adapt__.
Cooperate with InterfaceClass to ensure there is no performance penalty for this. Fixes #3

+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| Benchmark                                                   | bench_master38 | bench_issue3                 | bench_issue3_opt             |
+=============================================================+================+==============================+==============================+
| call interface (provides; deep)                             | 369 ns         | 454 ns: 1.23x slower (+23%)  | not significant              |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (provides; wide)                             | 373 ns         | 457 ns: 1.22x slower (+22%)  | 365 ns: 1.02x faster (-2%)   |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (no alternate, no conform, not provided)     | 671 ns         | 760 ns: 1.13x slower (+13%)  | 636 ns: 1.06x faster (-5%)   |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (alternate, no conform, not provided)        | 395 ns         | 494 ns: 1.25x slower (+25%)  | not significant              |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (no alternate, valid conform, not provided)  | 250 ns         | not significant              | 227 ns: 1.10x faster (-9%)   |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (alternate, invalid conform, not provided)   | 348 ns         | 424 ns: 1.22x slower (+22%)  | not significant              |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
2020-04-06 09:14:45 -05:00
Jason Madden 1af83ef9f9
Add documentation for taggedValue and invariant. 2020-04-06 09:14:45 -05:00
Jason Madden 139bab56a7
Add more cross refs to documentation and fix a couple sphinx warnings about duplicates in the index. 2020-04-06 09:14:45 -05:00
Jason Madden 6c2f71487e
Merge pull request #201 from zopefoundation/issue200
Remove the bare except: statements.
2020-04-06 09:06:48 -05:00
Jason Madden 719851072c
More micro benchmarks.
Comparing to current master, there is no substantial difference.

+-------------------------------------------------------------+----------------+------------------------------+
| Benchmark                                                   | bench_master38 | bench_issue200               |
+=============================================================+================+==============================+
| call interface (alternate, no conform, not provided)        | 395 ns         | 414 ns: 1.05x slower (+5%)   |
+-------------------------------------------------------------+----------------+------------------------------+
| call interface (no alternate, valid conform, not provided)  | 250 ns         | 240 ns: 1.04x faster (-4%)   |
+-------------------------------------------------------------+----------------+------------------------------+
| read __module__                                             | 45.3 ns        | 43.4 ns: 1.04x faster (-4%)  |
+-------------------------------------------------------------+----------------+------------------------------+
| query adapter (no registrations)                            | 3.23 ms        | 3.31 ms: 1.02x slower (+2%)  |
+-------------------------------------------------------------+----------------+------------------------------+
| query adapter (all trivial registrations)                   | 3.93 ms        | 4.40 ms: 1.12x slower (+12%) |
+-------------------------------------------------------------+----------------+------------------------------+
| query adapter (all trivial registrations, wide inheritance) | 43.3 us        | 45.5 us: 1.05x slower (+5%)  |
+-------------------------------------------------------------+----------------+------------------------------+
| query adapter (all trivial registrations, deep inheritance) | 43.2 us        | 46.9 us: 1.09x slower (+9%)  |
+-------------------------------------------------------------+----------------+------------------------------+
| sort mixed                                                  | 361 us         | 354 us: 1.02x faster (-2%)   |
+-------------------------------------------------------------+----------------+------------------------------+
| contains (populated dict: interfaces)                       | 61.3 ns        | 59.7 ns: 1.03x faster (-3%)  |
+-------------------------------------------------------------+----------------+------------------------------+

Not significant (13): call interface (provides; deep); call interface (provides; wide); call interface (no alternate, no conform, not provided); call interface (alternate, invalid conform, not provided); read __name__; read __doc__; read providedBy; sort interfaces; sort implementedBy; contains (empty dict); contains (populated list: interfaces); contains (populated dict: implementedBy); contains (populated list: implementedBy)
2020-04-02 10:35:51 -05:00
Jason Madden a4ed0566f9
MS VS stuck on c89 strikes again. 2020-04-02 08:10:23 -05:00
Jason Madden 84872a8d2a
Remove the bare except: statements.
Only catch AttributeError instead of everything.

Fixes #200

Note that this does break a doctest in five.intid (it's expecting a TypeError but it now gets Acquisition's RuntimeError).
2020-04-02 07:53:05 -05:00
Jason Madden abf12ada0a
Back to development: 5.0.3 2020-03-30 09:43:48 -05:00
Jason Madden 59715c4508
Preparing release 5.0.2 2020-03-30 09:42:51 -05:00
Jason Madden f20604d5ca
Merge pull request #198 from zopefoundation/issue197
Ensure that objects that implement no interfaces still have Interface in iro and sro
2020-03-30 09:41:32 -05:00
Jason Madden bfedd6f587
Ensure that objects that implement no interfaces still have Interface in their iro and sro.
Fixes #197.
2020-03-30 08:55:56 -05:00
Jason Madden 1b83ad47e4
Back to development: 5.0.2 2020-03-21 08:24:27 -05:00
Jason Madden 023f1d5c83
Preparing release 5.0.1 2020-03-21 08:24:00 -05:00
Jason Madden b614a6cf8f
Merge pull request #195 from zopefoundation/issue192-issue194
Make the RO for InterfaceClass consistent and fix handling of the STRICT_IRO
2020-03-21 08:22:39 -05:00
Jason Madden a11e1ea7ce
Make the RO for InterfaceClass consistent and fix handling of the STRICT_IRO env variable.
Fixes #192 and fixes #194.

Also fix the IRO for OrderedDict on CPython 2
2020-03-20 10:16:44 -05:00
Jason Madden 3a50f2e887
Back to development: 5.0.1 2020-03-19 07:45:53 -05:00
Jason Madden 953ba424a6
Preparing release 5.0.0 2020-03-19 07:45:28 -05:00
Jason Madden 6c98b3381a
Merge branch 'faster-eq-hash-comparison' 2020-03-19 07:40:56 -05:00
Jason Madden 04152ae7d2
Another comment update, referencing #163 2020-03-19 07:36:50 -05:00
Jason Madden 42c5ad2d4f
Update comments and add a test for more coverage. 2020-03-19 06:54:33 -05:00
Jason Madden dc719e296d
Remove untested except in the metaclass __new__.
Reviewers weren't sure how it could be raised.
2020-03-18 16:59:11 -05:00
Jason Madden 6be183e34d
Add additional tests for assigning to Interface.__module__. 2020-03-18 12:29:51 -05:00
Jason Madden a2687a6425
Add tests for comparing InterfaceClass/Implements objects to things without the required attributes.
And fix the C handling of this case.
2020-03-18 12:28:13 -05:00
Jason Madden 1094bee45c
Several small tweaks to GC and deletion handling.
Several places needed to, essentially, call super.
2020-03-18 12:27:20 -05:00
Jason Madden a9d90f4418
Move to a metaclass for handling __module__.
This offers the absolute best performance at what seems like reasonable complexity.

+-------------------------------------------------------------+----------------+-------------------------------+
| Benchmark                                                   | 38-master-full | 38-faster-meta                |
+=============================================================+================+===============================+
| read __module__                                             | 41.8 ns        | 40.9 ns: 1.02x faster (-2%)   |
+-------------------------------------------------------------+----------------+-------------------------------+
| read __name__                                               | 41.8 ns        | 39.9 ns: 1.05x faster (-5%)   |
+-------------------------------------------------------------+----------------+-------------------------------+
| read providedBy                                             | 56.9 ns        | 58.4 ns: 1.03x slower (+3%)   |
+-------------------------------------------------------------+----------------+-------------------------------+
| query adapter (no registrations)                            | 3.85 ms        | 2.95 ms: 1.31x faster (-24%)  |
+-------------------------------------------------------------+----------------+-------------------------------+
| query adapter (all trivial registrations)                   | 4.62 ms        | 3.63 ms: 1.27x faster (-21%)  |
+-------------------------------------------------------------+----------------+-------------------------------+
| query adapter (all trivial registrations, wide inheritance) | 51.8 us        | 42.2 us: 1.23x faster (-19%)  |
+-------------------------------------------------------------+----------------+-------------------------------+
| query adapter (all trivial registrations, deep inheritance) | 52.0 us        | 41.7 us: 1.25x faster (-20%)  |
+-------------------------------------------------------------+----------------+-------------------------------+
| sort interfaces                                             | 234 us         | 29.9 us: 7.84x faster (-87%)  |
+-------------------------------------------------------------+----------------+-------------------------------+
| sort mixed                                                  | 569 us         | 340 us: 1.67x faster (-40%)   |
+-------------------------------------------------------------+----------------+-------------------------------+
| contains (empty dict)                                       | 135 ns         | 55.2 ns: 2.44x faster (-59%)  |
+-------------------------------------------------------------+----------------+-------------------------------+
| contains (populated dict: interfaces)                       | 137 ns         | 56.1 ns: 2.45x faster (-59%)  |
+-------------------------------------------------------------+----------------+-------------------------------+
| contains (populated list: interfaces)                       | 39.7 us        | 2.96 us: 13.42x faster (-93%) |
+-------------------------------------------------------------+----------------+-------------------------------+
| contains (populated dict: implementedBy)                    | 137 ns         | 55.2 ns: 2.48x faster (-60%)  |
+-------------------------------------------------------------+----------------+-------------------------------+
| contains (populated list: implementedBy)                    | 40.6 us        | 24.1 us: 1.68x faster (-41%)  |
+-------------------------------------------------------------+----------------+-------------------------------+

Not significant (2): read __doc__; sort implementedBy
2020-03-18 12:27:20 -05:00
Jason Madden d9f06470f9
Use a descriptor for __module__
This makes the rest of the attribute access fast again, but slows down
__module__.

+-------------------------------------------+------------+-------------------------------+
| Benchmark                                 | 38-master3 | 38-faster-descr               |
+===========================================+============+===============================+
| read __module__                           | 41.1 ns    | 123 ns: 2.99x slower (+199%)  |
+-------------------------------------------+------------+-------------------------------+
| read __name__                             | 41.3 ns    | 39.9 ns: 1.04x faster (-3%)   |
+-------------------------------------------+------------+-------------------------------+
| read __doc__                              | 41.8 ns    | 42.4 ns: 1.01x slower (+1%)   |
+-------------------------------------------+------------+-------------------------------+
| query adapter (no registrations)          | 3.85 ms    | 2.95 ms: 1.30x faster (-23%)  |
+-------------------------------------------+------------+-------------------------------+
| query adapter (all trivial registrations) | 4.59 ms    | 3.67 ms: 1.25x faster (-20%)  |
+-------------------------------------------+------------+-------------------------------+
| contains (empty dict)                     | 136 ns     | 54.8 ns: 2.48x faster (-60%)  |
+-------------------------------------------+------------+-------------------------------+
| contains (populated dict)                 | 137 ns     | 55.7 ns: 2.46x faster (-59%)  |
+-------------------------------------------+------------+-------------------------------+
| contains (populated list)                 | 40.2 us    | 2.86 us: 14.03x faster (-93%) |
+-------------------------------------------+------------+-------------------------------+

Not significant (1): read providedBy
2020-03-18 12:27:20 -05:00
Jason Madden 413e716f9f
Avoid use of a metaclass by implementeng __getattribute__.
This is pretty, but it slows down all attribute access to interfaces.
By up to 25%. I'm not sure that's acceptable for things like
Interface.providedBy.

+-------------------------------------------+------------+-------------------------------+
| Benchmark                                 | 38-master3 | 38-faster3                    |
+===========================================+============+===============================+
| read __module__                           | 41.1 ns    | 44.3 ns: 1.08x slower (+8%)   |
+-------------------------------------------+------------+-------------------------------+
| read __name__                             | 41.3 ns    | 51.6 ns: 1.25x slower (+25%)  |
+-------------------------------------------+------------+-------------------------------+
| read __doc__                              | 41.8 ns    | 53.3 ns: 1.28x slower (+28%)  |
+-------------------------------------------+------------+-------------------------------+
| read providedBy                           | 56.7 ns    | 71.6 ns: 1.26x slower (+26%)  |
+-------------------------------------------+------------+-------------------------------+
| query adapter (no registrations)          | 3.85 ms    | 2.95 ms: 1.31x faster (-23%)  |
+-------------------------------------------+------------+-------------------------------+
| query adapter (all trivial registrations) | 4.59 ms    | 3.65 ms: 1.26x faster (-20%)  |
+-------------------------------------------+------------+-------------------------------+
| contains (empty dict)                     | 136 ns     | 55.4 ns: 2.45x faster (-59%)  |
+-------------------------------------------+------------+-------------------------------+
| contains (populated dict)                 | 137 ns     | 55.0 ns: 2.49x faster (-60%)  |
+-------------------------------------------+------------+-------------------------------+
| contains (populated list)                 | 40.2 us    | 2.95 us: 13.62x faster (-93%) |
+-------------------------------------------+------------+-------------------------------+
2020-03-18 12:27:20 -05:00
Jason Madden 7afd59d869
Fix tests when zope.component is also importable. 2020-03-18 12:26:35 -05:00
Jason Madden 5f4bb3f8ec
Clean up linter errors in test_interface.py so new/real problems are more obvious. 2020-03-18 12:26:35 -05:00
Jason Madden 01e0a7e36c
Benchmarks looking up adapters from components.
Current results (this branch vs master, 354faccebd):

| Benchmark                                 | 38-master | 38-faster                     |
|-------------------------------------------|-----------|-------------------------------|
| query adapter (no registrations)          | 3.81 ms   | 3.03 ms: 1.26x faster (-20%)  |
| query adapter (all trivial registrations) | 4.65 ms   | 3.90 ms: 1.19x faster (-16%)  |
| contains (empty dict)                     | 163 ns    | 76.1 ns: 2.14x faster (-53%)  |
| contains (populated dict)                 | 162 ns    | 76.9 ns: 2.11x faster (-53%)  |
| contains (populated list)                 | 40.3 us   | 3.09 us: 13.04x faster (-92%) |

Also need benchmarks using inheritance. The 'implied' data structures
are also hash/equality based.
2020-03-18 12:26:35 -05:00
Jason Madden b9165b790c
Fix doctest by making sure the default type repr can be used. 2020-03-18 12:26:35 -05:00
Jason Madden 8ac3bd088d
Move Interface hashing and comparison to C; 2.5 to 15x speedup in micro benchmarks
Included benchmark numbers:

Current master, Python 3.8:

.....................
contains (empty dict): Mean +- std dev: 198 ns +- 5 ns
.....................
contains (populated dict): Mean +- std dev: 197 ns +- 6 ns
.....................
contains (populated list): Mean +- std dev: 53.1 us +- 1.2 us

This code:

.....................
contains (empty dict): Mean +- std dev: 77.9 ns +- 2.3 ns
.....................
contains (populated dict): Mean +- std dev: 78.4 ns +- 3.1 ns
.....................
contains (populated list): Mean +- std dev: 3.69 us +- 0.08 us

So anywhere from 2.5 to 15x faster. Not sure how that will translate to
larger benchmarks, but I'm hopeful.

It turns out that messing with ``__module__`` is nasty, tricky
business, especially when you do it from C. Everytime you define a new
subclass, the descriptors that you set get overridden by the type
machinery (PyType_Ready). I'm using a data descriptor and a meta class
right now to avoid that but I'm not super happy with that and would
like to find a better way. (At least, maybe the data part of the
descriptor isn't necessary?) It may be needed to move more code into
C, I don't want a slowdown accessing ``__module__`` either; copying
around the standard PyGetSet or PyMember descriptors isn't enough
because they don't work on the class object (so
``classImplements(InterfaceClass, IInterface)`` fails).
2020-03-18 12:26:35 -05:00
Jason Madden 13de77d4ed
Merge pull request #188 from zopefoundation/issue8
Ensure Interface is the last item in the __sro__.
2020-03-18 12:25:23 -05:00
Jason Madden 4c4e1c985f
Ensure Interface is the last item in the __sro__.
None of the elegant solutions mentioned in the issue worked out, so I had to brute force it.

Fixes #8
2020-03-18 12:06:17 -05:00
Jason Madden 9e399071f0
Move the one-base optimization down a level, and enable using pre-calculated __sro__ for caching.
In my local 'load the world' test, this went from ~7800 full C3 merges to about ~1100.

Also take steps to avoid triggering false positive warnings about changed ROs when it's *just* Interface that moved.
2020-03-18 12:06:17 -05:00
Jason Madden bd5a749b5b
Merge pull request #189 from zopefoundation/issue136-issue134
Documentation clarifications.
2020-03-18 11:59:47 -05:00
Jason Madden 0f80d05343
Merge pull request #191 from zopefoundation/issue190
Make Interface.getTaggedValue follow the __iro__.
2020-03-18 11:55:36 -05:00
Jason Madden e1e94a0da9
More minor documentation fixups.
Mostly formatting. Some interfaces were being documented as clasess, which doesn't work.
2020-03-18 09:55:33 -05:00
Jason Madden f4b777d4a5
Make Interface.getTaggedValue follow the __iro__.
Previously it manually walked up __bases__, meaning the answers could be inconsistent.

Fixes #190.

Also fixes several minor issues in the documentation, mostly cross-reference related.
2020-03-18 07:44:12 -05:00
Jason Madden 771721fccf
Documentation clarifications.
- docs/adapter.rst
  Subscriptions are returned from least to most specific, not the other way around; the docs were incorrect.

  Add additional examples, and use more verbose names in current examples, to clarify this. Fixes #136.
- interfaces.py
  names() and namesAndDescriptions() just return a collection, not a sequence. Fixes #134.
2020-03-17 07:06:54 -05:00
Jason Madden d0c6a5967a
Merge pull request #182 from zopefoundation/issue21
Use C3 (mostly) to compute IRO.
2020-03-17 05:22:10 -05:00
Jason Madden 024f643227
Use C3 (mostly) to compute IRO.
Fixes #21

The 'mostly' is because interfaces are used in cases that C3 forbids;
when there's a conflict, we fallback to the legacy algorithm. It turns
out there are few conflicts (13K out of 149K total orderings in Plone).

I hoped the fix for #8 might shake out automatically, but it didn't.

Optimize the extremely common case of a __bases__ of length one.

In the benchmark, 4/5 of the interfaces and related objects have a base of length one.

Fix the bad IROs in the bundled ABC interfaces, and implement a way to get warnings or errors.

In running plone/buildout.coredev and tracking the RO requests, the
stats for equal, not equal, and inconsistent-so-fallback, I got
{'ros': 148868, 'eq': 138461, 'ne': 10407, 'inconsistent': 12934}

Add the interface module to the Attribute str.

This was extremely helpful tracking down the Plone problem; IDate is defined in multiple modules.
2020-03-15 09:56:14 -05:00
Michael Howitz 7d638c3b14 MacOS wheels for 3.8
Copy-pasted from `persistent` as suggested by @mgedmin
2020-03-13 08:14:24 +01:00
Jason Madden 354faccebd
Merge pull request #181 from zopefoundation/issue11
Make provided/implementedBy and adapter registries respect super().
2020-03-10 06:16:45 -05:00
Jason Madden fb8180d452
Add additional low-level tests for super() unwrapping. 2020-03-10 05:57:39 -05:00
Jason Madden 364fd0caf8
Remove unused str variables
The DEFINE_STRING macro prevents the linter from seeing them as unused
so I temporarily redefined it to find all such variables.
2020-03-10 05:56:07 -05:00
Marius Gedminas 4afc5ec8ac Print $TRAVIS_TAG in build logs
This is intended to help us solve mysteries like
https://github.com/zopefoundation/zope.interface/issues/185#issuecomment-596994265,
where a 5.0.0.dev0 release was uploaded despite there being no git tags
pointing to the relevant commit that anyone knows about.
2020-03-10 11:50:51 +02:00
Marius Gedminas 6b7861f199 Ask zest.releaser not to upload wheels
Because the wheel you get is not accepted by PyPI, so this makes the
entire upload step fail.
2020-03-10 09:55:00 +02:00
Marius Gedminas e5221d3afe Update changelog 2020-03-10 09:54:22 +02:00
Jason Madden 1e720c3819
Make provided/implementedBy and adapter registries respect super().
The query functions now start by looking at the next class in the MRO (interfaces directly provided by the underlying object are not found).

Adapter registries automatically pick up providedBy change to start finding the correct implementations of adapters, but to make that really useful they needed to change to unpack super() arguments and pass __self__ to the factory.

Fixes #11

Unfortunately, this makes PyPy unable to build the C extensions.

Additional crash-safety for adapter lookup.

Make the C functions get the cache only after resolving the
``required`` into a tuple, in case of side-effects like...clearing the
cache. This could lead to the ``cache`` object being deallocated
before we used it.

Drop the ``tuplefy`` function in favor of a direct call to
``PySequence_Tuple``. It's what the ``tuple`` constructor would do
anyway and saves a few steps.

Make sure that getting ``providedBy(super())`` and
``implementedBy(super())`` have no side effects.
2020-03-09 12:51:18 -05:00