Version 0.14.3
0.14.3 (13 April 2021) - Testing and all that jazz edition:
New:
unpythonic.test.fixtures, a lightweight testing framework for macro-enabled Python code.- Context managers
session,testset, andcatch_signals. Various helper functions, such asreturns_normally(for use in atest[]). - Testing macros, similar to the builtin
assert, but with the magic of conditions and restarts: even if a test fails or errors out, further tests continue running.test[expr],test[expr, message],test_raises[exctype, expr],test_raises[exctype, expr, message],test_signals[exctype, expr],test_signals[exctype, expr, message].- To help diagnose test failures with minimum fuss, the
test[...]macro provides an optional markerthe[expr]to capture the values of interesting subexpressions inside atest[...], for display in the test failure message (along with the corresponding source code).- Often even that is not needed; by default, if no
the[]are present,test[]captures the value of the leftmost term when the test is a comparison (common use case).
- Often even that is not needed; by default, if no
- Helper macros
fail[message],error[message]andwarn[message]for producing unconditional failures, errors or warnings.
- Context managers
callsite_filename: return the filename from which this function is being called. Useful as a building block for debug utilities and similar.equip_with_traceback: take a manually created exception instance, equip it with a traceback. Requires Python 3.7 or later.subset: test whether an iterable is a subset of another. Convenience function.allsame: test whether all elements of an iterable are the same. Sometimes useful in writing testing code.safeissubclass: like issubclass, but ifclsis not a class, swallow theTypeErrorand returnFalse. Sometimes useful when dealing with lots of code that needs to check types dynamically.
Non-breaking changes:
snow has a convenience mode for generating cyclic infinite sequences.mis nowimathifyandmgis nowgmathify, for descriptiveness, and for consistency with naming other abstractions inunpythonic. The old names will remain working in v0.14.x, and will be removed in v0.15.0.@genericand@typedcan now decorate instance methods, class methods and static methods. This makes those methods (OOP sense) have methods (generic function sense). Get it?selfandclsparameters do not participate in dispatching, and need no type annotation.- Beside appearing as the first positional-or-keyword parameter, the self-like parameter must be named one of
self,this,cls, orklassto be detected by the ignore mechanism. This limitation is due to implementation reasons; while a class body is being evaluated, the context needed to distinguish a method (OOP sense) from a regular function is not yet present. - OOP inheritance support: when
@genericis installed on an OOP method (instance method, or@classmethod), then at call time, classes are tried in MRO order. All generic-function methods of the OOP method defined in the class currently being looked up are tested for matches first, before moving on to the next class in the MRO. (This has subtle consequences, related to in which class in the hierarchy the various generic-function methods for a particular OOP method are defined.) - To work with OOP inheritance,
@genericmust be the outermost decorator (except@classmethodor@staticmethod, which are essentially compiler annotations). - However, when installed on a
@staticmethod, the@genericdecorator does not support MRO lookup, because that would make no sense. See discussions on interaction between@staticmethodandsuperin Python: [1] [2].
- To ease installation, relax version requirement of the optional MacroPy dependency to the latest released on PyPI, 1.1.0b2.
- Once MacroPy updates, we'll upgrade; 1.1.0b2 is missing some small features we would like to use (particularly the
.transformattribute of macros, which allows calling the underlying syntax transformer function).
- Once MacroPy updates, we'll upgrade; 1.1.0b2 is missing some small features we would like to use (particularly the
- Conditions: when an unhandled
errororcerroroccurs, the original unhandled error is now available in the__cause__attribute of theControlErrorexception that is raised in this situation. - Conditions: on Python 3.7+,
signalnow equips the condition instance with a traceback, for consistency withraise. - Document named-arg bug in
curryin the docstring. See #61. Fixing this needs a betterpartial, so for now it's a known issue. - All of
unpythonicitself is now tested using the new testing framework for macro-enabled code,unpythonic.test.fixtures. Hence, developingunpythonicnow requires MacroPy. For usingunpythonic, MacroPy remains strictly optional, as it will at least for the foreseeable future.
Breaking changes:
- Experimental:
@genericno longer takes a master definition. Methods (in the generic function sense) are registered directly with@generic; the first method definition implicitly creates the generic function.
Fixed:
- Compatibility with Pythons 3.4, 3.5 and 3.7, thanks to a newly set up CI workflow for automated multi-version testing. Also test coverage (statement coverage) is measured by the workflow.
- Significantly improved test coverage, from 85% to 92%. See #68. Many small bugs fixed.
- PyPy3 support: fixed crash in querying the arity of builtin functions. See #67.
- Condition system:
with handlerscatches also derived types, e.g. a handler forExceptionnow catches a signaledValueError.signal(SomeExceptionClass)now implicitly creates an instance with no arguments, just likeraisedoes.- Conditions can now inherit from
BaseException, not only fromException.
mogrifynow skipsnil, actually making it useful for processinglllinked lists. Although this is technically a breaking change, the original behavior was broken, so it should not affect any existing code.