Unpythonic

Latest version: v0.15.1

Safety actively analyzes 613461 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 1 of 7

0.15.2

*No user-visible changes yet.*


---

0.15.1

**New**:

- **Python 3.10 support**. Running on Python 3.10 requires `mcpyrate` 3.6.0.
- New module `unpythonic.timeutil`, with utilities for converting a number of seconds into human-understood formats (`seconds_to_human`, `format_human_time`), and a simple running-average `ETAEstimator` that takes advantage of these. As usual, these are available at the top level of `unpythonic`.
- Add function `unpythonic.syntax.get_cc`, the less antisocial little sister of `call_cc` from an alternate timeline, to make programming with continuations slightly more convenient. (Alternate timelines happen a lot when one uses multi-shot continuations.) The two work together. See docstring.
- Tag continuation closures (generated by the `with continuations` macro), for introspection.
- To detect at run time whether a given object is a continuation function, use the function `unpythonic.syntax.iscontinuation`.
- This is purely an introspection feature; `unpythonic` itself does not use this information. For why you might want to query this, see `get_cc`, particularly the [examples in unit tests](unpythonic/syntax/tests/test_conts.py).
- The information is stored as an attribute on the function object; keep this in mind if you intend to wrap the continuation function with another function. (Strictly, this is the correct behavior, since a custom wrapper is not a continuation function generated by the `with continuations` macro.)

**Fixed**:

- The test framework `unpythonic.test.fixtures` is now correctly installed when installing `unpythonic`. See [81](https://github.com/Technologicat/unpythonic/issues/81).
- The subpackage for live REPL functionality, `unpythonic.net`, is now correctly installed when installing `unpythonic`.
- Fix a broken import that prevented the REPL server `unpythonic.net.server` from starting. This was broken by the move of `async_raise` into `unpythonic.excutil` in 0.15.0.
- `unpythonic.syntax.prefix`: Fix wrong macro name in error message of `unpythonic.syntax.prefix.u`. Document in the docstring that the magic operators `q`, `u`, and `kw` (of the `prefix` macro) cannot be renamed by as-importing.
- Preserve the source location info of the dialect-import statement in the example dialects in [`unpythonic.dialects`](unpythonic/dialects/). In the output, the lines of expanded source code that originate in a particular dialect template are marked as coming from the unexpanded source line that contains the corresponding dialect-import.
- If you want to see the line numbers before and after dialect expansion, use the `StepExpansion` dialect from `mcpyrate.debug`.
- This fix requires `mcpyrate` 3.6.0 or later. The code will run also on earlier versions of `mcpyrate`; then, just like before, it will look as if all lines that originate in any dialect template came from the beginning of the user source code.


---

0.15.0

Beside introducing **dialects** (a.k.a. whole-module code transforms), this edition concentrates on upgrading our dependencies, namely the macro expander, and the Python language itself, to ensure `unpythonic` keeps working for the next few years. This introduces some breaking changes, so we have also taken the opportunity to apply any such that were previously scheduled.

We have sneaked in some upgrades for other subsystems, too. Particularly `curry`, the multiple dispatch system (`generic`), and the integration between these two have been improved significantly.

**IMPORTANT**:

- Minimum Python language version is now 3.6.
- We support 3.6, 3.7, 3.8, 3.9 and PyPy3 (language versions 3.6 and 3.7).
- For future plans, see our [Python language version support status](https://github.com/Technologicat/unpythonic/issues/1).
- The optional macro expander is now [`mcpyrate`](https://github.com/Technologicat/mcpyrate).

If you still need `unpythonic` for Python 3.4 or 3.5, use version 0.14.3, which is the final version of `unpythonic` that supports those language versions.

The same applies if you need the macro parts of `unpythonic` (i.e. import anything from `unpythonic.syntax`) in your own project that uses MacroPy. Version 0.14.3 of `unpythonic` works up to Python 3.7.


**New**:

- **Dialects!** New module `unpythonic.dialects`, providing [some example dialects](doc/dialects.md) that demonstrate what can be done with a [dialects system](https://github.com/Technologicat/mcpyrate/blob/master/doc/dialects.md) (i.e. full-module code transformer) together with a kitchen-sink language extension macro package such as `unpythonic`.
- These dialects have been moved from the now-obsolete [`pydialect`](https://github.com/Technologicat/pydialect) project and ported to use [`mcpyrate`](https://github.com/Technologicat/mcpyrate).

- **Improved robustness**: several auxiliary syntactic constructs now detect *at macro expansion time* if they appear outside any valid lexical context, and raise `SyntaxError` (with a descriptive message) if so.
- The full list is:
- `call_cc[]`, for `with continuations`
- `it`, for `aif[]`
- `local[]`/`delete[]`, for `do[]`
- `q`/`u`/`kw`, for `with prefix`
- `where`, for `let[body, where(k0=v0, ...)]` (also for `letseq`, `letrec`, `let_syntax`, `abbrev`)
- `with expr`/`with block`, for `with let_syntax`/`with abbrev`
- Previously these constructs could only raise an error at run time, and not all of them could detect the error even then.

- **Syntactic consistency**: allow env-assignment notation and brackets to declare bindings in the `let` family of macros. The preferred syntaxes for the `let` macro are now:

python
let[x << 42, y << 9001][...] lispy expr
let[[x << 42, y << 9001] in ...] haskelly let-in
let[..., where[x << 42, y << 9001]] haskelly let-where

If there is just one binding, these become:
python
let[x << 42][...]
let[[x << 42] in ...]
let[..., where[x << 42]]

Similarly for `letseq`, `letrec`, and the decorator versions; and for the expr forms of `let_syntax`, `abbrev`. The reason for preferring this notation is that it is consistent with both `unpythonic`'s env-assignments (`let` bindings live in an `env`) and the use of brackets to denote macro invocations.

To ease backwards compatibility, we still accept the syntax used up to v0.14.3, too.

Also, from symmetry and usability viewpoints, if a mix of brackets and parentheses are used, it hardly makes sense to require some specific mix - so this has been extended so that the choice of delimiter doesn't matter. All the following are also accepted, with the meaning exactly the same as above:
python
let[[x, 42], [y, 9001]][...] best visual consistency
let[(x, 42), (y, 9001)][...]
let([x, 42], [y, 9001])[...]
let((x, 42), (y, 9001))[...] like up to v0.14.3
let[[[x, 42], [y, 9001]] in ...] best visual consistency
let[[(x, 42), (y, 9001)] in ...]
let[([x, 42], [y, 9001]) in ...]
let[((x, 42), (y, 9001)) in ...] like up to v0.14.3
let[(x << 42, y << 9001) in ...]
let[..., where[[x, 42], [y, 9001]]] best visual consistency
let[..., where[(x, 42), (y, 9001)]]
let[..., where([x, 42], [y, 9001])]
let[..., where((x, 42), (y, 9001))] like up to v0.14.3
let[..., where(x << 42, y << 9001)]

For a single binding, these are also accepted:
python
let[x, 42][...]
let(x, 42)[...] like up to v0.14.3
let[[x, 42] in ...]
let[(x, 42) in ...] like up to v0.14.3
let[(x << 42) in ...]
let[..., where[x, 42]]
let[..., where(x, 42)] like up to v0.14.3
let[..., where(x << 42)]

These alternate syntaxes will be supported at least as long as we accept parentheses to pass macro arguments; but in new code, please use the preferred syntaxes.

- **Miscellaneous.**
- `with namedlambda` now understands the walrus operator, too. In the construct `f := lambda ...: ...`, the lambda will get the name `f`. (Python 3.8 and later.)
- `with namedlambda` now auto-names lambdas that don't have a name candidate using their source location info, if present. This makes it easy to see in a stack trace where some particular lambda was defined.
- Multiple-dispatch system `unpythonic.dispatch`:
- Use consistent terminology:
- The function that supports multiple call signatures is a *generic function*.
- Its individual implementations are *multimethods*.
- Add decorator `augment`: add a multimethod to a generic function defined elsewhere.
- Add function `isgeneric` to detect whether a callable has been declared `generic`.
- Add function `methods`: display a list of multimethods of a generic function.
- It is now possible to dispatch on a homogeneous type of contents collected by a `**kwargs` parameter.
- `curry` now supports `generic` functions. **This feature is experimental. Semantics may still change.**
- The utilities `arities`, `required_kwargs`, and `optional_kwargs` now support `generic` functions. **This feature is experimental. Semantics may still change.**
- `curry` now errors out immediately on argument type mismatch.
- Add `partial`, a type-checking wrapper for `functools.partial`, that errors out immediately on argument type mismatch.
- Add `unpythonic.excutil.reraise_in` (expr form), `unpythonic.excutil.reraise` (block form): conveniently remap library exception types to application exception types. Idea from [Alexis King (2016): Four months with Haskell](https://lexi-lambda.github.io/blog/2016/06/12/four-months-with-haskell/).
- Add variants of the above for the conditions-and-restarts system: `unpythonic.conditions.resignal_in`, `unpythonic.conditions.resignal`. The new signal is sent using the same error-handling protocol as the original signal, so that e.g. an `error` remains an `error` even if re-signaling changes its type.
- Add `resolve_bindings_partial`, useful for analyzing partial application.
- Add `triangular`, to generate the triangular numbers (1, 3, 6, 10, ...).
- Add `partition_int_triangular` to answer a timeless question concerning stackable plushies.
- Add `partition_int_custom` to answer unanticipated similar questions.
- All documentation files now have a quick navigation section to skip to another part of the docs. (For all except the README, it's at the top.)
- Python 3.8 and 3.9 support added.


**Non-breaking changes**:

- **Changes to how some macros expand.**
- Some macros, notably `letseq`, `do0`, and `lazyrec`, now expand into hygienic macro captures of other macros. The `continuations` macro also outputs a hygienically captured `aif` when transforming an `or` expression that occurs in tail position.
- This allows `mcpyrate.debug.step_expansion` to show the intermediate result, as well as brings the implementation closer to the natural explanation of how these macros are defined. (Zen of Python: if the implementation is easy to explain, it *might* be a good idea.)
- The implicit do (extra bracket syntax) also expands as a hygienically captured `do`, but e.g. in `let[]` it will then expand immediately (due to `let`'s inside-out expansion order) before control returns to the macro stepper. If you want to see the implicit `do[]` invocation, use the `"detailed"` mode of the stepper, which shows individual macro invocations even when expanding inside-out: `step_expansion["detailed"][...]`, `with step_expansion["detailed"]:`.

- The `do[]` and `do0[]` macros now expand outside-in. The main differences from a user perspective are:
- Any source code captures (such as those performed by `test[]`) show the expanded output of `do` and `do0`, because that's what they receive. (For tests, you may want to use the macro `with expand_testing_macros_first`, which see.)
- `mcpyrate.debug.step_expansion` is able to show the intermediate result after the `do` or `do0` has expanded, but before anything else has been done to the tree.

- **Miscellaneous.**
- Resolve issue [61](https://github.com/Technologicat/unpythonic/issues/61): `curry` now supports kwargs properly.
- We now analyze parameter bindings like Python itself does, so it should no longer matter whether arguments are passed by position or by name.
- Positional passthrough works as before. Named passthrough added.
- Any remaining arguments (that cannot be accepted by the initial call) are passed through to a callable intermediate result (if any), and then outward on the curry context stack as a `Values`. Since `curry` in this role is essentially a function-composition utility, the receiving curried function instance unpacks the `Values` into args and kwargs.
- If any extra arguments (positional or named) remain when the top-level curry context exits, then by default, `TypeError` is raised. To override, use `with dyn.let(curry_context=["whatever"])`, just like before. Then you'll get a `Values` object.
- The generator instances created by the gfuncs returned by `gmemoize`, `imemoize`, and `fimemoize`, now support the `__len__` and `__getitem__` methods to access the already-yielded, memoized part. Asking for the `len` returns the current length of the memo. For subscripting, both a single `int` index and a slice are accepted. Note that memoized generators do **not** support all of the [`collections.abc.Sequence`](https://docs.python.org/3/library/collections.abc.html) API, because e.g. `__contains__` and `__reversed__` are missing, on purpose.
- `fup`/`fupdate`/`ShadowedSequence` can now walk the start of a memoized infinite replacement backwards. (Use `imemoize` on the original iterable, instantiate the generator, and use that generator instance as the replacement.)
- When using the `autoreturn` macro, if the item in tail position is a function definition or class definition, return the thing that was defined.
- The `nb` macro now works together with `autoreturn`.
- `unpythonic.conditions.signal`, when the signal goes unhandled, now returns the canonized input `condition`, with a nice traceback attached. This feature is intended for implementing custom error protocols on top of `signal`; `error` already uses it to produce a nice-looking error report.
- The internal exception types `unpythonic.conditions.InvokeRestart` and `unpythonic.ec.Escape` now inherit from `BaseException`, so that they are not inadvertently caught by `except Exception` handlers.
- The modules `unpythonic.dispatch` and `unpythonic.typecheck`, which provide the `generic` and `typed` decorators and the `isoftype` function, are no longer considered experimental. From this release on, they receive the same semantic versioning guarantees as the rest of `unpythonic`.
- CI: Automated tests now run on Python 3.6, 3.7, 3.8, 3.9, and PyPy3 (language versions 3.6, 3.7).
- CI: Test coverage improved to 94%.
- Full update pass for the user manual written in Markdown.
- Things added or changed in 0.14.2 and later are still mentioned as such, and have not necessarily been folded into the main text. But everything should be at least up to date now.


**Breaking changes**:

- **New macro expander `mcpyrate`; MacroPy support dropped**.
- **API differences.**
- Macro arguments are now passed using brackets, `macroname[args][...]`, `with macroname[args]`, `macroname[args]`, instead of parentheses.
- Parentheses are still available as alternative syntax, because up to Python 3.8, decorators cannot have subscripts (so e.g. `dlet[(x, 42)]` is a syntax error, but `dlet((x, 42))` is fine). This has been fixed in Python 3.9.
- If you already only run on Python 3.9 and later, please use brackets, that is the preferred syntax. We currently plan to eventually drop support for parentheses to pass macro arguments in the future, when Python 3.9 becomes the minimum supported language version for `unpythonic`.
- If you write your own macros, note `mcpyrate` is not drop-in compatible with MacroPy or `mcpy`. See [its documentation](https://github.com/Technologicat/mcpyrate#documentation) for details.
- **Behavior differences.**
- `mcpyrate` should report test coverage for macro-using code correctly; no need for ` pragma: no cover` in block macro invocations or in quasiquoted code.

- **Previously scheduled API changes**.
- As promised, names deprecated during 0.14.x have been removed. Old name on the left, new name on the right:
- `m` → `imathify` (consistency with the rest of `unpythonic`)
- `mg` → `gmathify` (consistency with the rest of `unpythonic`)
- `setescape` → `catch` (Lisp family standard name)
- `escape` → `throw` (Lisp family standard name)
- `getvalue`, `runpipe` → `exitpipe` (combined into one)
- **CAUTION**: `exitpipe` already existed in v0.14.3, but beginning with v0.15.0, it is now an `unpythonic.symbol.sym` (like a Lisp symbol). This is not compatible with existing, pickled `exitpipe` instances; it used to be an instance of the class `Getvalue`, which has been removed. (There's not much reason to pickle an `exitpipe` instance, but we're mentioning this for the sake of completeness.)
- Drop support for deprecated argument format for `raisef`. Now the usage is `raisef(exc)` or `raisef(exc, cause=...)`. These correspond exactly to `raise exc` and `raise exc from ...`, respectively.

- **Other backward-incompatible API changes.**
- Multiple-return-value handling changed. Resolves issue [32](https://github.com/Technologicat/unpythonic/issues/32).
- Multiple return values are now denoted as `Values`, available from the top-level namespace of `unpythonic`.
- The `Values` constructor accepts both positional and named arguments. Passing in named arguments creates **named return values**. This completes the symmetry between argument passing and returns.
- Most of the time, it's still fine to return a tuple and destructure that; but in contexts where it is important to distinguish between a single `tuple` return value and multiple return values, it is preferable to use `Values`.
- In any utilities that deal with function composition, if your intent is multiple-return-values, **it is now mandatory to return a `Values`** instead of a `tuple`:
- `curry`
- `pipe` family
- `compose` family
- `unfold`
- `iterate`
- All multiple-return-values in code using the `with continuations` macro. (The continuations system essentially composes continuation functions.)
- The lazy evaluation tools `lazy`, `Lazy`, and the quick lambda `f` (underscore notation for Python) are now provided by `unpythonic` as `unpythonic.syntax.lazy`, `unpythonic.lazyutil.Lazy`, and `unpythonic.syntax.fn` (note name change!), because they used to be provided by `macropy`, and `mcpyrate` does not provide them.
- **API differences.**
- The quick lambda is now named `fn[]` instead of `f[]` (as in MacroPy). This was changed because `f` is often used as a function name in code examples, local temporaries, and similar. Also, `fn[]` is a less ambiguous abbreviation for a syntactic construct that means *function*, while remaining shorter than the equivalent `lambda`. Compare `fn[_ * 2]` and `lambda x: x * 2`, or `fn[_ * _]` and `lambda x, y: x * y`.
- Note that in `mcpyrate`, macros can be as-imported, so this change affects just the *default* name of `fn[]`. But that is exactly what is important: have a sensible default name, to remove the need to as-import so often.
- The macros `lazy` and `fn` can be imported from the syntax interface module, `unpythonic.syntax`, and the class `Lazy` is available at the top level of `unpythonic`.
- Unlike `macropy`'s `Lazy`, our `Lazy` does not define `__call__`; instead, it defines the method `force`, which has the same effect (it computes if necessary, and then returns the value of the promise). You can also use the function `unpythonic.force`, which has the extra advantage that it passes through a non-promise input unchanged (so you don't need to care whether `x` is a promise before calling `force(x)`; this is sometimes useful).
- When you import the macro `quicklambda`, you **must** import also the macro `fn`.
- The underscore `_` is no longer a macro on its own. The `fn` macro treats the underscore magically, as before, but anywhere else it is available to be used as a regular variable.
- **Behavior differences.**
- `fn[]` now respects nesting: an invocation of `fn[]` will not descend into another nested `fn[]`.
- The `with quicklambda` macro is still provided, and used just as before. Now it causes any `fn[]` invocations lexically inside the block to expand before any other macros in that block do.
- Since in `mcpyrate`, macros can be as-imported, you can rename `fn` at import time to have any name you want. The `quicklambda` block macro respects the as-import, by internally querying the expander to determine the name(s) the macro `fn` is currently bound to.
- For the benefit of code using the `with lazify` macro, laziness is now better respected by the `compose` family, `andf` and `orf`. The utilities themselves are marked lazy, and arguments will be forced only when a lazy function in the chain actually uses them, or when an eager (not lazy) function is encountered in the chain.
- Rename the `curry` macro to `autocurry`, to prevent name shadowing of the `curry` function. The new name is also more descriptive.
- Move the functions `force1` and `force` from `unpythonic.syntax` to `unpythonic`. Make the `Lazy` class (promise implementation) public. (They actually come from `unpythonic.lazyutil`.)
- Change parameter ordering of `unpythonic.it.window` to make it curry-friendly. Usage is now `window(n, iterable)`.
- This was an oversight when this function was added; most other functions in `unpythonic.it` have been curry-friendly from the beginning.
- Change output format of `resolve_bindings` to return an `inspect.BoundArguments` instead of the previous `OrderedDict` that had a custom format. Change the input format of `tuplify_bindings` to match.
- Change parameter name from `l` to `length` in the functions `in_slice` and `index_in_slice` (in the `unpythonic.collections` module).
- These are mostly used internally, but technically a part of the public API.
- This change fixes a `flake8` [E741](https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes) warning, and the new name for the parameter is more descriptive.

- **Miscellaneous.**
- Robustness: the `with continuations` macro now raises `SyntaxError` if async constructs (`async def` or `await`) appear lexically inside the block, because interaction of `with continuations` with Python's async subsystem has never been implemented. See [issue 4](https://github.com/Technologicat/unpythonic/issues/4).
- The functions `raisef`, `tryf`, `equip_with_traceback`, and `async_raise` now live in `unpythonic.excutil`. They are still available in the top-level namespace of `unpythonic`, as usual.
- The functions `call` and `callwith` now live in `unpythonic.funutil`. They are still available in the top-level namespace of `unpythonic`, as usual.
- The functions `almosteq`, `fixpoint`, `partition_int`, and `ulp` now live in `unpythonic.numutil`. They are still available in the top-level namespace of `unpythonic`, as usual.
- Remove the internal utility class `unpythonic.syntax.util.ASTMarker`. We now have `mcpyrate.markers.ASTMarker`, which is designed for data-driven communication between macros that work together. As a bonus, no markers are left in the AST at run time.
- Rename contribution guidelines to `CONTRIBUTING.md`, which is the modern standard name. Old name was `HACKING.md`, which was correct, but nowadays obscure.
- Python 3.4 and 3.5 support dropped, as these language versions have officially reached end-of-life.


**Fixed**:

- Make `unpythonic.misc.callsite_filename` ignore our call helpers. This allows the testing framework report the source code filename correctly when testing code using macros that make use of these helpers (e.g. `autocurry`, `lazify`).

- In `aif`, `it` is now only valid in the `then` and `otherwise` parts, as it should always have been.

- Fix docstring of `test`: multiple `the[]` marks were already supported in 0.14.3, as the macro documentation already said, but the docstring claimed otherwise.

- Fix bug in `with namedlambda`. Due to incorrect function arguments in the analyzer, already named lambdas were not detected correctly.

- Fix bug: `fup`/`fupdate`/`ShadowedSequence` now actually accept an infinite-length iterable as a replacement sequence (under the obvious usage limitations), as the documentation has always claimed.

- Fix bug: `memoize` is now thread-safe. Even when the same memoized function instance is called concurrently from multiple threads. Exactly one thread will compute the result. If `f` is recursive, the thread that acquired the lock is the one that is allowed to recurse into the memoized `f`.


---

0.14.3

**New**:

- `unpythonic.test.fixtures`, a lightweight testing framework **for macro-enabled Python code**.
- Context managers `session`, `testset`, and `catch_signals`. Various helper functions, such as `returns_normally` (for use in a `test[]`).
- 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 marker `the[expr]` to capture the values of interesting subexpressions inside a `test[...]`, 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).
- Helper macros `fail[message]`, `error[message]` and `warn[message]` for producing unconditional failures, errors or warnings.
- `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 if `cls` is not a class, swallow the `TypeError` and return `False`. Sometimes useful when dealing with lots of code that needs to check types dynamically.

**Non-breaking changes**:

- `s` now has a convenience mode for generating cyclic infinite sequences.
- `m` is now `imathify` and `mg` is now `gmathify`, for descriptiveness, and for consistency with naming other abstractions in `unpythonic`. **The old names will remain working in v0.14.x, and will be removed in v0.15.0.**
- `generic` and `typed` can now decorate instance methods, class methods and static methods. This makes those *methods (OOP sense)* have *methods (generic function sense)*. Get it?
- `self` and `cls` parameters 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`, or `klass` to 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 `generic` is installed on an OOP method (instance method, or `classmethod`), then at call time, classes are tried in [MRO](https://en.wikipedia.org/wiki/C3_linearization) 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, `generic` must be the outermost decorator (except `classmethod` or `staticmethod`, which are essentially compiler annotations).
- However, when installed on a `staticmethod`, the `generic` decorator does not support MRO lookup, because that would make no sense. See discussions on interaction between `staticmethod` and `super` in Python: [[1]](https://bugs.python.org/issue31118) [[2]](https://stackoverflow.com/questions/26788214/super-and-staticmethod-interaction/26807879).
- 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 `.transform` attribute of macros, which allows calling the underlying syntax transformer function).
- Conditions: when an unhandled `error` or `cerror` occurs, the original unhandled error is now available in the `__cause__` attribute of the `ControlError` exception that is raised in this situation.
- Conditions: on Python 3.7+, `signal` now equips the condition instance with a traceback, for consistency with `raise`.
- Document named-arg bug in `curry` in the docstring. See [61](https://github.com/Technologicat/unpythonic/issues/61). Fixing this needs a better `partial`, so for now it's a known issue.
- All of `unpythonic` itself is now tested using the new testing framework for macro-enabled code, `unpythonic.test.fixtures`. **Hence, developing `unpythonic` now requires MacroPy.** For **using** `unpythonic`, MacroPy remains strictly optional, as it will at least for the foreseeable future.

**Breaking changes**:

- *Experimental*: `generic` no 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](https://en.wikipedia.org/wiki/Continuous_integration) [workflow](https://github.com/Technologicat/unpythonic/actions) 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](https://github.com/Technologicat/unpythonic/issues/68). Many small bugs fixed.
- PyPy3 support: fixed crash in querying the arity of builtin functions. See [67](https://github.com/Technologicat/unpythonic/issues/67).
- Condition system:
- `with handlers` catches also derived types, e.g. a handler for `Exception` now catches a signaled `ValueError`.
- `signal(SomeExceptionClass)` now implicitly creates an instance with no arguments, just like `raise` does.
- Conditions can now inherit from `BaseException`, not only from `Exception.`
- `mogrify` now skips `nil`, actually making it useful for processing `ll` linked lists. Although this is technically a breaking change, the original behavior was broken, so it should not affect any existing code.

---

0.14.2

With the arrival of [conditions and restarts](http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html), and a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) server, I think it is now fair to say `unpythonic` contains an ad-hoc, informally-specified, slow implementation of half of Common Lisp. To avoid *bug-ridden*, we have tests - but it's not entirely impossible for some to have slipped through. If you find one, please file an issue [in the tracker](https://github.com/Technologicat/unpythonic/issues).

This release welcomes the first external contribution! Thanks to aisha-w for the much improved organization and presentation of the documentation!

**Language version**:

We target **Python 3.6**. Now we test on both **CPython** and **PyPy3**.

Rumors of the demise of Python 3.4 support are exaggerated. While the testing of `unpythonic` has moved to 3.6, there neither is nor will there be any active effort to intentionally drop 3.4 support until `unpythonic` reaches 0.15.0.

That is, support for 3.4 will likely be dropped with the arrival of the next batch of breaking changes. The current plan is visible in the roadmap [as the 0.15.0 milestone](https://github.com/Technologicat/unpythonic/milestone/1).

If you're still stuck on 3.4 and find something in the latest `unpythonic` 0.14.x doesn't work there, please file an issue. (Support for 0.14.x will end once 0.15 is released, but not before.)

**New**:

- Improve organization and presentation of documentation (28).
- Macro README: Emacs syntax highlighting for `unpythonic.syntax` and MacroPy.
- **Resumable exceptions**, a.k.a. *conditions and restarts*. One of the famous killer features of Common Lisp. Drawing inspiration from [python-cl-conditions](https://github.com/svetlyak40wt/python-cl-conditions/) by Alexander Artemenko. See `with restarts` (Common Lisp equivalent: `RESTART-CASE`), `with handlers` (`HANDLER-BIND`), `signal` (`SIGNAL`), `invoke` (`INVOKE-RESTART`). Many convenience forms are also exported; see `unpythonic.conditions` for a full list. For an introduction to conditions, see [Chapter 19 in Practical Common Lisp by Peter Seibel](http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html).
- **REPL server** and client. Interactively hot-patch your running Python program! Another of the famous killer features of Common Lisp. The server is daemonic, listening for connections in a background thread. (Don't worry, it's strictly opt-in.) See `unpythonic.net.server` and `unpythonic.net.client`.
- *Batteries for network programming*:
- `unpythonic.net.msg`: A simplistic message protocol for sending message data over a stream-based transport (such as TCP).
- `unpythonic.net.ptyproxy`: Proxy between a Linux [PTY](https://en.wikipedia.org/wiki/Pseudoterminal) and a network socket. Useful for serving terminal utilities over the network. This doesn't use `pty.spawn`, so Python libraries that expect to run in a terminal are also welcome. See `unpythonic.net.server` for a usage example.
- `unpythonic.net.util`: Miscellaneous small utilities.
- `fix`: Break infinite recursion cycles (for pure functions). Drawing inspiration from original implementations by [Matthew Might](http://matt.might.net/articles/parsing-with-derivatives/) and [Per Vognsen](https://gist.github.com/pervognsen/8dafe21038f3b513693e).
- More batteries for itertools:
- `fixpoint`: Arithmetic fixed-point finder (not to be confused with `fix`).
- `within`: Yield items from iterable until successive iterates are close enough (useful with [Cauchy sequences](https://en.wikipedia.org/wiki/Cauchy_sequence)).
- `chunked`: Split an iterable into constant-length chunks.
- `lastn`: Yield the last `n` items from an iterable.
- `pad`: Extend iterable to length `n` with a `fillvalue`.
- `interleave`: For example, `interleave(['a', 'b', 'c'], ['+', '*']) --> ['a', '+', 'b', '*', 'c']`. Interleave items from several iterables, slightly differently from `zip`.
- `find`: From an iterable, get the first item matching a given predicate. Convenience function.
- `powerset`: Compute the power set (set of all subsets) of an iterable. Works also for infinite iterables.
- `CountingIterator`: Count how many items have been yielded, as a side effect.
- `slurp`: Extract all items from a `queue.Queue` (until it is empty) into a list, returning that list.
- `map`: Curry-friendly thin wrapper for the builtin `map`, making it mandatory to specify at least one iterable.
- `running_minmax`, `minmax`: Extract both min and max in one pass over an iterable. The `running_` variant is a scan and returns a generator; the just-give-me-the-final-result variant is a fold.
- `ulp`: Given a float `x`, return the value of the unit in the last place (the "least significant bit"). At `x = 1.0`, this is the [machine epsilon](https://en.wikipedia.org/wiki/Machine_epsilon), by definition of the machine epsilon.
- `partition_int`: split a small positive integer, in all possible ways, into smaller integers that sum to it.
- `dyn` now supports rebinding, using the assignment syntax `dyn.x = 42`. To mass-update atomically, see `dyn.update`.
- `box` now supports `.set(newvalue)` to rebind (returns the new value as a convenience), and `unbox(b)` to extract contents. Syntactic sugar for rebinding is `b << newvalue` (where `b` is a box).
- `ThreadLocalBox`: A box with thread-local contents. It also holds a default object, which is used when a particular thread has not placed any object into the box.
- `Some`: An immutable box. Useful for optional fields; tell apart the presence of a `None` value (`Some(None)`) from the absence of a value (`None`).
- `Shim`: A shim holds a `box` or a `ThreadLocalBox`, and redirects attribute accesses to whatever object is currently in the box. The point is that the object in the box can be replaced with a different one later, while keeping the attribute proxy in place. One use case is to redirect standard output only in particular threads.
- `islice` now supports negative start and stop. (**Caution**: no negative step; and it must consume the whole iterable to determine where it ends, if at all.)
- `async_raise`: Inject KeyboardInterrupt into an arbitrary thread. (*CPython only*.)
- `resolve_bindings`: Get the parameter bindings a given callable would establish if it was called with the given args and kwargs. This is mainly of interest for implementing memoizers, since this allows them to see (e.g.) `f(1)` and `f(a=1)` as the same thing for `def f(a): pass`.
- `Singleton`: a base class for singletons that interacts properly with `pickle`. The pattern is slightly pythonified; instead of silently returning the same instance, attempting to invoke the constructor while an instance already exists raises `TypeError`. This solution separates concerns better; see [22](https://github.com/Technologicat/unpythonic/issues/22).
- `sym`: a lispy symbol type; or in plain English: a lightweight, human-readable, process-wide unique marker, that can be quickly compared to another such marker by object identity (`is`). These named symbols are *interned*. Supplying the same name to the constructor results in receiving the same object instance. Symbols survive a `pickle` roundtrip.
- `gensym`: a utility to create a new, unique *uninterned* symbol. Like the pythonic idiom `nonce = object()`, but with a human-readable label, and with `pickle` support. Object identity of gensyms is determined by an UUID, generated when the symbol is created. Gensyms also survive a `pickle` roundtrip.

**Experimental features**:

Each experimental feature is a provisional proof-of-concept, usually lacking battle-testing and polish. Details may still change in a backwards-incompatible way, or the whole feature may still be removed. Do not depend on it in production!

- **Multiple dispatch**. The `generic` decorator makes a generic function with multiple dispatch. Arity and type annotations determine which method of the generic function a specific call of the function is dispatched to.
- This essentially allows replacing the `if`/`elif` dynamic type checking boilerplate of polymorphic functions with type annotations on the function parameters, with support for features from the `typing` stdlib module.
- Inspired by the [multi-methods of CLOS](http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html) (the Common Lisp Object System), and the [generic functions of Julia](https://docs.julialang.org/en/v1/manual/methods/).
- `typed`: The little sister of the `generic` decorator. Restrict allowed argument types to one specific combination only.
- `isoftype`: The big sister of `isinstance`. Type check a value against a type specification at run time, with support for many (but not all) features from the [`typing`](https://docs.python.org/3/library/typing.html) module. This is the machinery that powers `generic` and `typed`.
- If you need a run-time type checker for serious general use, consider the [`typeguard`](https://github.com/agronholm/typeguard) library.

**Non-breaking changes**:

- `setescape`/`escape` have been renamed `catch`/`throw`, to match the standard terminology in the Lisp family. **The old nonstandard names are now deprecated, and will be removed in 0.15.0.**
- The parameters of `raisef` are now more pythonic, just the object `exc` and an optional keyword-only `cause`. **Old-style parameters are now deprecated, and will be removed in 0.15.0.** See [30](https://github.com/Technologicat/unpythonic/issues/30).
- `runpipe` and `getvalue` are now both replaced by a single unified name `exitpipe`. This is just a rename, with no functionality changes. **The old names are now deprecated, and will be removed in 0.15.0.**
- Accessing the `.x` attribute of a `box` directly is now deprecated. It does not work with `ThreadLocalBox`, which must handle things differently due to implementation reasons. Instead, use the API, which works for both types of boxes. `b << newvalue` (syntactic sugar) or `b.set(newvalue)` sends a different object into the box, and `unbox(b)` (syntactic sugar) or `b.get()` retrieves the current value.
- The `dbg[]` macro now works in the REPL, too. See [12](https://github.com/Technologicat/unpythonic/issues/12).
- The `namedlambda` block macro now also names lambdas that are:
- Passed as a named argument of a function call, as in ``foo(f=lambda ...: ...)``; or
- Inside a dictionary literal, with a literal string key, as in ``{"f": lambda ...: ...}``. See [40](https://github.com/Technologicat/unpythonic/issues/40).
- Move macro documentation to `doc/macros.md`. (Was `macro_extras/README.md`.)
- Add contribution guidelines, `HACKING.md`.

**Fixed**:

- Fix initialization crash in `lazyutil` if MacroPy is not installed.
- Fix bug in `identity` and `const` with zero args ([7](https://github.com/Technologicat/unpythonic/issues/7)).
- Use standard Python semantics for negative indices ([6](https://github.com/Technologicat/unpythonic/issues/6)).
- Escape continuation analysis in `unpythonic.syntax.util` now interprets also the literal name `throw` as invoking an escape continuation.
- Fix pickling of `frozendict` ([55](https://github.com/Technologicat/unpythonic/issues/55)).
- Fix spurious cache misses in memoizers ([26](https://github.com/Technologicat/unpythonic/issues/26)). The bug affected `memoize`, `gmemoize`, `fix` and `fixtco`.

---

0.14.1

**Language version**:

- Support Python 3.6. First released in 2016, supported until 2021, most distros should have it by now.
- This will be the final release that supports Python 3.4; upstream support for 3.4 ended in March 2019.

**New**:

- ``Popper``, a pop-while iterator.
- ``window``, a length-n sliding window iterator for general iterables.
- ``autoref[]`` can now be nested.
- ``dbg[]`` now supports also an expression variant, customizable by lexically assigning ``dbgprint_expr``. See the README on macros for details.

**Bugfixes**:

- Fix crash when SymPy or mpmath are not installed.
- ``mogrify`` is now part of the public API, as it should have been all along.
- Docs: Mention the ``mg`` function in the README.

**Non-breaking changes**:

- Future-proof ``namelambda`` for Python 3.8.
- Docs: ``dbg[]`` is now listed as a convenience feature in the README.

---

Page 1 of 7

© 2024 Safety CLI Cybersecurity Inc. All Rights Reserved.