-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathCHANGES.txt
451 lines (301 loc) · 13.4 KB
/
CHANGES.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
CHANGES
*******
0.13 (unreleased)
=================
- Drop support for Python below 3.6
- Use GitHub Actions for CI
0.12 (2020-01-29)
=================
- **Breaking change**
reg.arginfo(callable) returns now a FullArgSpec tuple
instead of the deprecated ArgSpec tuple. FullArgSpec has
full support for annotations and keyword-only parameters.
Fixes `#55`_.
.. _#55: https://github.com/morepath/reg/issues/55
- **Removed**: Removed support for Python 2.
You have to upgrade to Python 3 if you want to use this version.
- Dropped support for Python 3.3.
- Added support for Python 3.5, 3.6, 3.7, 3.8 and PyPy 3.6.
- Make Python 3.7 the default testing environment.
- Add integration for the Black code formatter.
0.11 (2016-12-23)
=================
- **Breaking change**
The ``key_predicate`` function is gone. You can now use
``Predicate(..., index=KeyIndex)`` or ``match_key`` instead.
- **Breaking change**
The ``class_predicate`` function is gone. You can now use
``Predicate(..., index=ClassIndex)``, ``match_instance`` or
``match_class`` instead.
- **Breaking change**
The undocumented ``Sentinel`` class and ``NOT_FOUND`` object are
gone.
- **Breaking change**
The class ``PredicateRegistry`` is not longer part of the API.
Internally, the classes ``MultiPredicate``, ``MultiIndex``,
``SingleValueRegistry`` have all been merged into
``PredicateRegistry``, which should now considered an implementation
detail.
- The second argument for ``match_key`` is now optional; if you
don't supply it ``match_key`` will generate a predicate function
that extracts that name by default.
- The documentation now includes a section describing the internals of
Reg.
- Upload universal wheels to pypi during release.
0.10 (2016-10-04)
=================
- **Breaking change**
Reg has undergone another API breaking change. The goals of this
change were:
* Make everything explicit.
* A simpler implementation structure -- dispatch functions maintain
their own registries, which allows for less interacting objects.
* Make the advanced context-dependent dispatch more Pythonic by
using classes with special dispatch methods.
Detailed changes:
* ``reg.Registry`` is gone. Instead you register directly on the
dispatch function::
@reg.dispatch('a')
def foo(a):
...
def foo_implementation(a):
...
foo.register(foo_implementation, a=Document)
* Caching is now per dispatch function, not globally per lookup. You
can pass a ``get_key_lookup`` function that wraps
``reg.PredicateRegistry`` instance inside a
``reg.DictCachingKeyLookup`` cache. You can also use a
``reg.LruCachingKeyLookup`` if you expect a dispatch to be called
with a large amount of possible predicate combinations, to
preserve memory.
* The whole concept of a "lookup" is gone:
* ``reg.implicit`` is gone: everything is explicit. There is no more
implicit lookup.
* ``reg.Lookup`` itself is gone -- its now implemented directly in the
dispatch object, but was already how you accessed it.
* The special ``lookup`` argument to pass through the current
``Lookup`` is gone. If you need context-dependent dispatch, you
use dispatch methods.
* If you need context dependent dispatch, where the functions
being dispatched to depend on application context (such as
Morepath's application mounting), you use
``reg.dispatch_method`` to create a dispatch method. A dispatch
method maintains an entirely separate dispatch registry for each
subclass. You use ``reg.methodify`` to register a dispatch
function that takes an optional context first argument.
If you do not use the context-dependent dispatch feature, then to
upgrade your code:
* remove any ``reg.set_implicit`` from your code, setup of
``Lookup`` and the like.
* If you use an explicit ``lookup`` argument you can just remove them.
* You also need to change your registration code: no more
``reg.Registry`` setup.
* Change your registrations to be on the dispatch objects itself
using ``Dispatch.register``.
* To enable caching you need to set up ``get_key_lookup`` on the
dispatch functions. You can create a partially applied version of
``dispatch`` to make this less verbose::
import reg
from functools import partial
def get_caching_key_lookup(r):
return reg.CachingKeyLookup(r, 5000, 5000, 5000)
dispatch = partial(reg.dispatch, get_key_lookup=get_caching_key_lookup)
* ``dispatch_external_predicates`` is gone. Just use ``dispatch``
directly. You can add predicates to an existing Dispatch object
using the ``add_predicates`` method.
If you do use the context-dependent dispatch feature, then you also
need to:
* identify the context class in your application (or create one).
* move the dispatch functions to this class, marking them with
``@reg.dispatch_method`` instead of ``@reg.dispatch``.
* Registration is now using
``<context_class>.<method>.register``. Functions you register this
way behave as methods to ``context_class``, so get an instance of
this class as the first argument.
* You can also use ``reg.methodify`` to register implementation
functions that do not take the context as the first argument --
this is useful when upgrading existing code.
* Call your context-dependent methods as methods on the context
instance. This way you can indicate what context you are calling
your dispatch methods in, instead of using the `lookup`` argument.
In some cases you want a context-dependent method that actually does
not dispatch on any of its arguments. To support this use case you
can simply set function (that takes an app argument) as a the method
on the context class directly::
Context.my_method = some_function
If you want to set up a function that doesn't take a reference to a
``Context`` instance as its first argument, you can use
``reg.methodify`` to turn it into a method that ignores its first
argument::
Context.my_method = reg.methodify(some_function)
If you want to register a function that might or might not have a
reference to a ``Context`` instance as its first argument, called,
e.g., ``app``, you can use the following::
Context.my_method = reg.methodify(some_function, selfname='app')
- **Breaking change**
Removed the helper function ``mapply`` from the API.
- **Breaking change**
Removed the exception class ``KeyExtractorError`` from the API.
When passing the wrong number of arguments to a dispatch function,
or when using the wrong argument names, you will now get a
TypeError, in conformity with standard Python behaviour.
- **Breaking change**
Removed the ``KeyExtractor`` class from the API. Callables used in
predicate construction now expect the same arguments as the dispatch
function.
- **Breaking change**
Removed the ``argnames`` attribute from ``Predicate`` and its
descendant.
- **Breaking change**
Remove the ``match_argname`` predicate. You can now use
``match_instance`` with no callable instead.
- The second argument for ``match_class`` is now optional; if you
don't supply it ``match_class`` will generate a predicate function
that extracts that name by default.
- The second argument for ``match_instance`` is now optional; if you
don't supply it ``match_instance`` will generate a predicate function
that extracts that name by default.
- Include doctests in Tox and Travis.
- We now use virtualenv and pip instead of buildout to set up the
development environment. The development documentation has been
updated accordingly.
- As we reached 100% code coverage for pytest, coveralls integration
was replaced by the ``--fail-under=100`` argument of ``coverage
report`` in the tox coverage test.
0.9.3 (2016-07-18)
==================
- Minor fixes to documentation.
- Add tox test environments for Python 3.4 and 3.5, PyPy 3 and PEP 8.
- Make Python 3.5 the default Python environment.
- Changed location ``NoImplicitLookupError`` was imported from in
``__init__.py``.
0.9.2 (2014-11-13)
==================
- Reg was a bit too strict; when you had multiple (but not single)
predicates, Reg would raise KeyError when you put in an unknown
key. Now they're just being silently ignored, as they don't do any
harm.
- Eliminated a check in ``ArgExtractor`` that could never take place.
- Bring test coverage back up to 100%.
- Add converage configuration to ignore test files in coverage
reporting.
0.9.1 (2014-11-11)
==================
- A bugfix in the behavior of the fallback logic. In situations with
multiple predicates of which one is a class predicate it was
possible for a fallback not to be found even though a fallback was
available.
0.9 (2014-11-11)
================
Total rewrite of Reg! This includes a range of changes that can break
code. The primary motivations for this rewrite:
* unify predicate system with class-based lookup system.
* extract dispatch information from specific arguments instead of all
arguments.
Some specific changes:
* Replaced ``@reg.generic`` decorator with ``@reg.dispatch()``
decorator. This decorator can be configured with predicates that
extract information from the arguments. Rewrite this::
@reg.generic
def foo(obj):
pass
to this::
@reg.dispatch('obj')
def foo(obj):
pass
And this::
@reg.generic
def bar(a, b):
pass
To this::
@reg.dispatch('a', 'b')
def bar(a, b):
pass
This is to get dispatch on the classes of these instance
arguments. If you want to match on the class of an attribute of
an argument (for instance) you can use ``match_instance``
with a function::
@reg.dispatch(match_instance('a', lambda a: a.attr))
The first argument to ``match_instance`` is the name of the
predicate by which you refer to it in ``register_function``.
You can also use ``match_class`` to have direct dispatch on classes
(useful for replicating classmethods), and ``match_key`` to have
dispatch on the (immutable) value of the argument (useful for a view
predicate system). Like for ``match_instance``, you supply functions
to these match functions that extract the exact information to
dispatch on from the argument.
* The ``register_function`` API replaces the ``register`` API to
register a function. Replace this::
r.register(foo, (SomeClass,), dispatched_to)
with::
r.register_function(foo, dispatched_to, obj=SomeClass)
You now use keyword parameters to indicate exactly those arguments
specified by ``reg.dispatch()`` are actually predicate
arguments. You don't need to worry about the order of predicates
anymore when you register a function for it.
* The new ``classgeneric`` functionality is part of the predicate
system now; you can use ``reg.match_class`` instead. Replace::
@reg.classgeneric
def foo(cls):
pass
with::
@reg.dispatch(reg.match_class('cls', lambda cls: cls))
def foo(cls):
pass
You can do this with any argument now, not just the first one.
* pep443 support is gone. Reg is focused on its own dispatch system.
* Compose functionality is gone -- it turns out Morepath doesn't use
lookup composition to support App inheritance. The cached lookup
functionality has moved into ``registry.py`` and now also supports
caching of predicate-based lookups.
* Dependency on the future module is gone in favor of a small amount
of compatibility code.
0.8 (2014-08-28)
================
- Added a ``@reg.classgeneric``. This is like ``@reg.generic``, but
the first argument is treated as a class, not as an instance. This
makes it possible to replace ``@classmethod`` with a generic
function too.
- Fix documentation on running documentation tests. For some reason
this did not work properly anymore without running sphinxpython
explicitly.
- Optimization: improve performance of generic function calls by
employing ``lookup_mapply`` instead of general ``mapply``, as we
only care about passing in the lookup argument when it's defined,
and any other arguments should work as before. Also added a
``perf.py`` which is a simple generic function timing script.
0.7 (2014-06-17)
================
- Python 2.6 compatibility. (Ivo van der Wijk)
- Class maps (and thus generic function lookup) now works with old
style classes as well.
- Marked as production/stable now in ``setup.py``.
0.6 (2014-04-08)
================
- Removed unused code from mapply.py.
- Typo fix in API docs.
0.5 (2014-01-21)
================
- Make ``reg.ANY`` public. Used for predicates that match any value.
0.4 (2014-01-14)
================
- arginfo has been totally rewritten and is now part of the public API of reg.
0.3 (2014-01-06)
================
- Experimental Python 3.3 support thanks to the future module.
0.2 (2013-12-19)
================
- If a generic function implementation defines a ``lookup`` argument
that argument will be the lookup used to call it.
- Added ``reg.mapply()``. This allows you to call things with more
keyword arguments than it accepts, ignoring those extra keyword
args.
- A function that returns ``None`` is not assumed to fail, so no fallback
to the original generic function is triggered anymore.
- An optional ``precalc`` facility is made available on ``Matcher`` to
avoid some recalculation.
- Implement a specific ``PredicateMatcher`` that matches a value on
predicate.
0.1 (2013-10-28)
================
- Initial public release.