Skip to content

Version 0.14.2.1

Compare
Choose a tag to compare
@Technologicat Technologicat released this 07 Aug 13:42
· 1439 commits to master since this release

0.14.2.1 just fixes that I forgot the include the final release date for 0.14.2 in CHANGELOG.md. Real release below.

0.14.2 7 August 2020 - "Greenspun" edition:

With the arrival of conditions and restarts, and a REPL 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.

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.

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 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.
  • 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 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 and Per Vognsen.
  • 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).
    • 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, 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.
  • 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 (the Common Lisp Object System), and the generic functions of Julia.
  • 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 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 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.
  • 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.
  • 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.
  • 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).
  • Use standard Python semantics for negative indices (#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).
  • Fix spurious cache misses in memoizers (#26). The bug affected memoize, gmemoize, fix and fixtco.