Package hdict

Expand source code
#  Copyright (c) 2023. Davi Pereira dos Santos
#  This file is part of the hdict project.
#  Please respect the license - more about this in the section (*) below.
#
#  hdict is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  hdict is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with hdict.  If not, see <http://www.gnu.org/licenses/>.
#
#  (*) Removing authorship by any means, e.g. by distribution of derived
#  works or verbatim, obfuscated, compiled or rewritten versions of any
#  part of this work is illegal and it is unethical regarding the effort and
#  time spent here.
#
from typing import TypeVar

from hdict.content.argument.apply import apply
from hdict.content.argument.field import field
from hdict.content.argument.sample import sample
from hdict.data.empty_ import Empty_
from hdict.content.value import value
from hdict.data.frozenhdict import frozenhdict
from hdict.data.hdict_ import hdict_
from hdict.data.self_ import Self_
from hdict.expression.step.cache import cache

__all__ = ["hdict", "_", "Ø", "apply", "field", "sample", "frozenhdict", "value", "cache"]

VT = TypeVar("VT")


class hdict(hdict_):
    """
    Function id is reversed before application.
    This is needed to enable handling a function as a value, under the original id.

    >>> from hdict import hdict, apply, field
    >>> from hdict.content.argument.default import default
    >>> d = hdict({"x": 3}, y=5)
    >>> d["alpha"] = 11
    >>> d.show(colored=False)
    {
        x: 3,
        y: 5,
        alpha: 11,
        _id: e6WGyTj7trk6AUUcdxGAefyG.T9j.SvBdEsHF.r5,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            alpha: A1RyW.GoA3q9-iCbCvWyWClExm1J3wI.ok6UA3Nk
        }
    }
    >>> d >>= {"beta": 12, "gamma": 17}
    >>> d["p1", "q1"] = apply(lambda x, y=3: [x**y, x/y])
    >>> d["pq"] = apply(lambda x, y=3: [x**y, x/y])
    >>> d["p2", "q2"] = apply(lambda x=2, y=None: [x**y, x/y])
    >>> f = lambda x, y: {"a": x**y, "b": x/y}
    >>> d["z1", "w1"] = apply(f)
    >>> d["z2":"a", "w2":"b"] = apply(f)
    >>> d >>= {
    ...     "r1": apply(lambda x: x**2),
    ...     "r2": apply(lambda x: x**3),
    ...     "r3": apply(lambda x: x**4),
    ...     ("ra1", "rb1"): apply(f),
    ...     (("ra2", "a"), ("rb2", "b")): apply(f),
    ... }
    >>> d["z2"]
    243
    >>> d["zz1", "ww1"] = apply(f, field("r1"), y=field("r2"))
    >>> d >>= {("zz2", "ww2"): apply(f, y=field("r2"), x=9)}  # Define external value.
    >>> d >>= {"zzzz": apply(f, y=13, x=9)}
    >>> # Non-pickable custom classes need a custom 'hosh' attribute to be applied and also to be used as a value.
    >>> from hosh import Hosh
    >>> # Example of class that could be used as a value or as a function.
    >>> from dataclasses import dataclass
    >>> @dataclass
    ... class CustomClass:
    ...     hosh = Hosh.fromid("Some.arbitrary.identifier.with.length.40")
    ...     def __call__(self, x, y):
    ...         return x + y, x / y
    >>> custom = CustomClass()
    >>> d["f"] = custom  # Custom callable handled as a value.
    >>> d["zzz1", "www1"] = apply(custom, 11, y=33)  # Custom callable being applied.
    >>> d["zzz2", "www2"] = apply(field("f"), field("r1"), y=44)  # Callable field being applied.
    >>> d.show(colored=False)
    {
        x: 3,
        y: 5,
        alpha: 11,
        beta: 12,
        gamma: 17,
        p1: λ(x y)→0,
        q1: λ(x y)→1,
        pq: λ(x y),
        p2: λ(x y)→0,
        q2: λ(x y)→1,
        z1: λ(x y)→0,
        w1: λ(x y)→1,
        z2: 243,
        w2: λ(x y)→b,
        r1: λ(x),
        r2: λ(x),
        r3: λ(x),
        ra1: λ(x y)→0,
        rb1: λ(x y)→1,
        ra2: λ(x y)→a,
        rb2: λ(x y)→b,
        zz1: λ(x=r1 y=r2)→0,
        ww1: λ(x=r1 y=r2)→1,
        zz2: λ(9 y=r2)→0,
        ww2: λ(9 y=r2)→1,
        zzzz: λ(9 13),
        f: "CustomClass()",
        zzz1: λ(11 33)→0,
        www1: λ(11 33)→1,
        zzz2: λ(r1 44)→0,
        www2: λ(r1 44)→1,
        _id: i5wtTs5qggivS-y5TNuhnM5jwokjF132M7jF.49a,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            alpha: A1RyW.GoA3q9-iCbCvWyWClExm1J3wI.ok6UA3Nk,
            beta: WM5TbiaJ1gLqKRSFiY3VkZEu1PwQcaAokBKBPrWg,
            gamma: yb-HU.jSxd496XfId1J..MkX7xfUPJOL1-07hHdt,
            p1: Qs0J0I.AhR.brQjpYwUJqDNLk-zKd7FmG0g7gdd1,
            q1: VOAVwyrrdC7eIsjnVkqdpsqUfhprKzKriATFEOQI,
            pq: KtTWRcFQRKVgTJabGMgY-HAQWJ1TZGnOYw7NU.1K,
            p2: qb0H0MqNit0rLwk6CsC4Q2bxpCmBQ581eoGI39sr,
            q2: Sjsl-.MJJ3SK2.INLAJ-0R5BwlfG.tccIpxPFRtB,
            z1: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
            w1: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
            z2: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
            w2: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
            r1: FO3NXIQIi7TBFw1FqLRJYo13EA.uu4Y-L17Fmx0z,
            r2: HorxHsNCdpkm270yeTZ-vREjjFXWIYC99ALidDVU,
            r3: bWc33lXvXHIJXix5Jw2.Nhw0EIsv3TuAa7t8Ix5q,
            ra1: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
            rb1: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
            ra2: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
            rb2: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
            zz1: FB6W9j12qWZ34fUwyrBETzFuAXRB-xn7O1PGhr2j,
            ww1: IhchjkRfjLXpnsC6zl-TFugIQrnUIdB7Wsgpnely,
            zz2: LE5ohPby7q4dNu3qhqgucRcCt.pd87O.CyKWloqe,
            ww2: -RBf-UiccAG3sTH0UFC6C.YFmYcpTRA.0PFP6Oun,
            zzzz: Irbj-xVP8rEIPoylOTNmiuJ-lGdx0dpzIPgq-169,
            f: Some.arbitrary.identifier.with.length.40,
            zzz1: TBw0fUZZo1WlI9uczNuF0w4vC06u6YvzJyNPVEi1,
            www1: WqqXpIpMwinaXxYNqRjj4qttDcKXN.gcGjARpOSh,
            zzz2: .mJim0y-LMUYZi01GN8MTPkHj79JtFdREf7g40ug,
            www2: jwtsaf1IZMG6sWqprXZnc.n-ilyfncwhL3Qr.-Md
        }
    }
    >>> d["p1"]
    243
    >>> from hdict import value
    >>> d.evaluate()
    >>> d = hdict(x=2)
    >>> g = lambda x, y: [x + y, x / y]
    >>> d["z"] = apply(f, 2, y=3)
    >>> d["w", "v"] = apply(f, field("x"), y=33)
    >>> d["f"] = f
    >>> d = d >> apply(field("f"), field("x"), y=default(3), nonexistent_parameter=7)("w3", "v3") # todo: : nonexistent parameter should raise an exception
    >>> d >>= apply(field("f"), field("x"), y=default(3))("w", "v")
    >>> d["w2", "v2"] = apply(field("f"), field("x"), y=default(3))
    >>> d >>= {"z": apply(f, field("x"), y=3), ("w", "v"): apply(g, y=7)}
    >>> d >>= apply(f, field("x"), y=3)("z9") * apply(g, y=7)("w9", "v9")
    >>> pp = apply(f, field("x"), y=3)("z") >> apply(g, y=7)("w", "v")
    >>> d >>= {"x": 3} >> pp >> apply(g, y=7)("w", "v")
    >>> from hdict import _
    >>> a1 = apply(f, y=_(1, 2, 4, ..., 128))
    >>> a2 = apply(f, _(0, 3, 6, ..., 9), y=_(0, 3, 6, ..., 9))
    >>> ppp = hdict() >> a2.sample()("k", "t")
    >>> ppp.show(colored=False)
    {
        k: λ(9 9)→0,
        t: λ(9 9)→1,
        _id: dK-iumb4L5nkFVT9LCkdk3daQtuC.ORk6JwWMhnt,
        _ids: {
            k: rHTgwW.w2SsbcvBlSnWWddLH4vgyXlM1Fhxqr48f,
            t: IldA8m-uSN9lJcE4TBtjTcY-sSiA33mzxQ2k-wpN
        }
    }
    >>> ppp.k
    387420489
    >>> a1("z")
    z=λ(x y=~[1 2 .*. 128])
    >>> a2(w="a", v="b")
    (('w', 'a'), ('v', 'b'))=λ(x=~[0 3 .+. 9] y=~[0 3 .+. 9])
    >>> p = a1("z") >> a2(w="a", v="b")
    >>> h = lambda a, b=4: 5
    >>> app = apply(h, a=_(0, 3, 6, ..., 9))
    >>> app
    λ(a=~[0 3 .+. 9] b=default(4))
    >>> app.c
    c=λ(a=~[0 3 .+. 9] b=default(4))
    >>> sampled = app.sample(0).c
    >>> sampled
    c=λ(9 b=default(4))
    >>> r = hdict() >> sampled
    >>> r.show(colored=False)
    {
        c: λ(9 b=4),
        _id: Bbe5mzn0oCuHZ.Y84-jaEnh3jcrgD8av6IZezKEG,
        _ids: {
            c: 6EehD7OoZe2REI.1YsVLKxSF4hJoYxfOZJLbF.Aj
        }
    }
    >>> r.evaluated.show(colored=False)
    {
        c: 5,
        _id: Bbe5mzn0oCuHZ.Y84-jaEnh3jcrgD8av6IZezKEG,
        _ids: {
            c: 6EehD7OoZe2REI.1YsVLKxSF4hJoYxfOZJLbF.Aj
        }
    }
    >>> from random import Random
    >>> rnd = Random(0)
    >>> p1 = p.sample(rnd)
    >>> d["w"]
    10
    >>> d >>= p1
    >>> d["z"] = apply(f, 2, y=3)
    >>> d["w", "v"] = apply(f, _.x, y=_.x)
    >>> d["w", "v"] = apply(_.f, _.x, y=default(3))
    >>> d = hdict() >> {"z": apply(f, 7, y=3), ("w", "v"): apply(g, default(6), y=7)}
    >>> d = hdict(w=6) >> (apply(f, _["w"], y=3)(z="z") >> apply(g, x=_(1,2,3,...,5), y=7)("ww", "v")).sample(0)
    >>> p = apply(f, y=_(1, 2, 4, ..., 128))("z") >> apply(f, y=_(0, 3, 6, ..., 9))(w="a", v="b")
    >>> d.show(colored=False)
    {
        w: 6,
        z: λ(x=w 3)→z,
        ww: λ(4 7)→0,
        v: λ(4 7)→1,
        _id: x4TxaVuAymsh97Yr.15Oc1ekllvlpECk091124RM,
        _ids: {
            w: CZ7Jm5fQMZ3fZJ3kAVOi0FYK-exFqPqgoYLsGxGl,
            z: No1nN40OXnJ.zOyAvoxwCjyD06cUDiXTZQh4q8xa,
            ww: qZepp.wpXCOYQrwnVIwoZ4kR9pIuMGDQpvRevv80,
            v: wxkjBSP54cKEfxKE1Zte-2dDll3G9Nd-yDh3CLas
        }
    }
    >>> d = hdict(x=3) >> p.sample(rnd)
    >>> d.show(colored=False)
    {
        x: 3,
        z: λ(x 16),
        w: λ(x 9)→a,
        v: λ(x 9)→b,
        _id: 22b-e.CtRGVSoMkektNzHYSVZTouhL2jAHLyPd4Q,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            z: 64cxw0HmJ0fydH7By6i0HrbuwA759XexTu3Bu0Zd,
            w: p1Z5umNo12DHCZtKbh2EClW6TZxv.M447HlALWhv,
            v: HbYbR1RjPdU4jixjW7xSxslRpYx9W6Oiay7maK6F
        }
    }
    >>> d1 = hdict(x=52, y=13)
    >>> d2 = hdict(x=value(52, hosh="1234567890123456789012345678901234567890"))
    >>> d1.show(colored=False)
    {
        x: 52,
        y: 13,
        _id: 5pwGP0LxQRbQaDEk9ztQ4V4qz.A-IIhVNTrcyt8U,
        _ids: {
            x: c.llz05T6ZXw5AlsU4xfmMxcvvHZhLl60LckZis9,
            y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
        }
    }
    >>> d2.show(colored=False)
    {
        x: 52,
        _id: kYzgpPdRgQSYSEpp1qt4EHQLQJXuyb2WDQS-iNPh,
        _ids: {
            x: 1234567890123456789012345678901234567890
        }
    }
    >>> d3 = d1 >> d2
    >>> d3.show(colored=False)
    {
        x: 52,
        y: 13,
        _id: -EFuy5NAeK.LIALpBiZKK-fYQmc9AZYQQck-HiRK,
        _ids: {
            x: 1234567890123456789012345678901234567890,
            y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
        }
    }
    >>> (d3 >> d1.frozen).show(colored=False)
    {
        x: 52,
        y: 13,
        _id: 5pwGP0LxQRbQaDEk9ztQ4V4qz.A-IIhVNTrcyt8U,
        _ids: {
            x: c.llz05T6ZXw5AlsU4xfmMxcvvHZhLl60LckZis9,
            y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
        }
    }

    >>> d = hdict(x=2, y=4)
    >>> {"x": 2, "y": 4} == d.frozen
    True
    >>> {"x": 2, "y": 4} == d
    True
    >>> d == {"x": 2, "y": 4}
    True
    >>> dict(d)
    {'x': 2, 'y': 4}
    >>> hdict() >> {"x": 3} == {"x": 3}
    True
    >>> {"x": 3, "d": {"x": 7}} == hdict(x=3, d=hdict(x=7))
    True
    >>> hdict(x=3, d=hdict(x=7)) == {"x": 3, "d": {"x": 7}}
    True
    >>> {"x": 3, "_id": hdict(x=3).id} == hdict(x=3)
    True
    >>> hdict(x=3) == {"x": 3, "_id": hdict(x=3).id}
    True
    >>> hdict(x=3) == hdict(x=3)
    True
    >>> hdict(x=3).frozen == hdict(x=3)
    True
    >>> hdict(x=3) != {"x": 4}
    True
    >>> hdict(x=3) != hdict(x=4)
    True
    >>> hdict(x=3).frozen != hdict(x=4)
    True
    >>> hdict(x=3) != {"y": 3}
    True
    >>> hdict(x=3) != {"x": 3, "_id": (~hdict(x=3).hosh).id}
    True
    >>> hdict(x=3) != hdict(y=3)
    True
    >>> del d["x"]
    >>> list(d)
    ['y']
    >>> e = d >> apply(lambda y: y*7)("y")
    >>> from hdict.content.aux_value import f2hosh
    >>> print(f2hosh(lambda y: y*7))
    54YCMDJIlsIvMQ.KJtT-vFyjg83Zgfj2xSHOgCj8
    >>> print(e)
    {y: "λ(4)"}
    >>> e.evaluate()
    >>> print(e)
    {y: 28}
    >>> d = d >> apply(lambda y=1: y*7, fhosh="54YCMDJIlsIvMQ.KJtT-vFyjg83Zgfj2xSHOgCj8")("y")
    >>> print(d)
    {y: "λ(4)"}
    >>> d.evaluate()
    >>> print(d)
    {y: 28}
    >>> hash(e.frozen) == hash(d.frozen)
    True
    >>> d = hdict(a=5) >> hdict(y=28)
    >>> d.show(colored=False)
    {
        a: 5,
        y: 28,
        _id: C-xKyWCyBL6g32KIuxoANoF9czLaJTh-emPsMqOg,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9
        }
    }
    >>> d >>= apply(lambda a: a)("x")
    >>> d.show(colored=False)
    {
        a: 5,
        y: 28,
        x: λ(a),
        _id: qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp
        }
    }
    >>> {"_id": "qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY"} == d
    True
    >>> d.show(colored=False)
    {
        a: 5,
        y: 28,
        x: λ(a),
        _id: qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp
        }
    }
    >>> def f():
    ...     print("busy")
    ...     return 23
    >>> storage = {}
    >>> d >>= apply(f).o >> cache(storage, "x", "y")
    >>> d.y
    28
    >>> d.show(colored=False)
    {
        a: 5,
        y: 28,
        x: ↑↓ cached at `dict`·,
        o: λ(),
        _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
            o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
        }
    }
    >>> d.evaluated.show(colored=False)
    busy
    {
        a: 5,
        y: 28,
        x: 5,
        o: 23,
        _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
            o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
        }
    }
    >>> d.evaluated.show(colored=False)
    {
        a: 5,
        y: 28,
        x: 5,
        o: 23,
        _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
            o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
        }
    }
    """


class Empty(Empty_):
    """
    >>> from hdict import _
    >>> d = _ >> {"x": 5} >> dict(y=7)
    >>> type(+_), type(d)
    (<class 'hdict.Empty'>, <class 'hdict.hdict'>)
    >>> d.show(colored=False)
    {
        x: 5,
        y: 7,
        _id: A0G3Y7KNMLihDvpSJ3tB.zxshc6u1CbbiiYjCAAA,
        _ids: {
            x: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: eJCW9jGsdZTD6-AD9opKwjPIOWZ4R.T0CG2kdyzf
        }
    }
    """


class Self(Self_):
    """"""


Ø = empty = Empty()
_ = Self()

Sub-modules

hdict.abs
hdict.content
hdict.data
hdict.dataset
hdict.expression
hdict.persistence
hdict.text

Classes

class apply (appliable: callable | apply | field, *applied_args, fhosh: Hosh = None, **applied_kwargs)

Function application

Single output application is defined by attribute: 'apply(f).my_output_field'. Multioutput application is defined by a call: 'apply(f)("output_field1", "output_field2")'.

>>> from hdict import apply, value, frozenhdict, _
>>> f = lambda a, b: a**b
>>> v = apply(f, 5, b=7)
>>> v
λ(5 7)
>>> g = lambda x, y: x**y
>>> apply(g, y=value(7777), x=v)
λ(x=λ(5 7) 7777)
>>> v2 = apply(f, a=v, b=value(7))
>>> v2
λ(a=λ(5 7) 7)
>>> v.enclosure({}, "j", None).value
78125
>>> v2.enclosure({}, "j", None)
λ(a=λ(5 7) 7)
>>> v2.enclosure({}, "j", None).value
17763568394002504646778106689453125
>>> f = lambda a,b, c=1,d=2,e=13: 0
>>> apply(f).requirements
{'a': field(a), 'b': field(b), 'c': default(1), 'd': default(2), 'e': default(13)}
>>> ap = apply(f,3)
>>> ap.requirements
{'a': 3, 'b': field(b), 'c': default(1), 'd': default(2), 'e': default(13)}
>>> ap
λ(3 b c=default(1) d=default(2) e=default(13))
>>> ap.enclosure({"b": value(77)}, "j", None)
λ(3 b c=1 d=2 e=13)
>>> ap
λ(3 b c=default(1) d=default(2) e=default(13))
>>> d = {"f": ap, "b": 5, "d": 1, "e": field("b")}
>>> d
{'f': λ(3 b c=default(1) d=default(2) e=default(13)), 'b': 5, 'd': 1, 'e': field(b)}
>>> from hdict.data.aux_frozendict import handle_items
>>> handle_items(d, previous=frozenhdict({"b": 5}))
{'b': 5, 'f': λ(3 b c=1 d=2 e=13), 'd': 1, 'e': 5}
>>> d
{'f': λ(3 b c=default(1) d=default(2) e=default(13)), 'b': 5, 'd': 1, 'e': field(b)}
>>> apply(f,3,4).requirements
{'a': 3, 'b': 4, 'c': default(1), 'd': default(2), 'e': default(13)}
>>> apply(f,3,4,5).requirements
{'a': 3, 'b': 4, 'c': 5, 'd': default(2), 'e': default(13)}
>>> apply(f,3,4,5,6).requirements
{'a': 3, 'b': 4, 'c': 5, 'd': 6, 'e': default(13)}
>>> apply(f,3,4,5,6,7).requirements
{'a': 3, 'b': 4, 'c': 5, 'd': 6, 'e': 7}
>>> apply(f,d=5).requirements
{'a': field(a), 'b': field(b), 'c': default(1), 'd': 5, 'e': default(13)}
>>> f = lambda a,b, *arg, c=1,d=2,e=13, **kwargs: 0
>>> apply(f,3,4,5,6,7,8).requirements
{'a': 3, 'b': 4, arg_2: 5, arg_3: 6, arg_4: 7, arg_5: 8, 'c': default(1), 'd': default(2), 'e': default(13)}
>>> apply(f,x=3,e=4,d=5,c=6,b=7,a=8).requirements
{'a': 8, 'b': 7, 'c': 6, 'd': 5, 'e': 4, 'x': 3}
>>> apply(f,3,c=77,x=5).requirements
{'a': 3, 'b': field(b), 'c': 77, 'd': default(2), 'e': default(13), 'x': 5}
>>> apply(f,b=77,x=5).requirements
{'a': field(a), 'b': 77, 'c': default(1), 'd': default(2), 'e': default(13), 'x': 5}
>>> from hdict.content.argument.entry import entry
>>> a = apply(lambda x: x.value * 7, x=entry("x"))
>>> c = {"x": 3, "y": entry("x")} >> a.r
>>> c.show(colored=False)
{
    x: 3,
    y: ·3,
    r: λ(·x),
    _id: bh0bgTZI.2f-WteZFpIrsMxJvZYUBydOfF3wFLV.,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        r: NoAit6.-dyFNiCZnoRAhY5zbJ0hc6u5lkQzYwBCx
    }
}
>>> b = a.x.sample()
>>> b
x=λ(·x)
>>> d = {"x": 3} >> b
>>> d.x
21
>>> a.sampleable
False
>>> a.sample()
λ(·x)
>>> d["h"] = frozenhdict(a=2)
>>> d.show(colored=False)
{
    x: 21,
    h: {
        a: 2,
        _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
        _ids: {
            a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
        }
    },
    _id: V8nyMrJbhGschQAaW3ZXD6uxvVRIluFmIFIkSaZ0,
    _ids: {
        x: NoAit6.-dyFNiCZnoRAhY5zbJ0hc6u5lkQzYwBCx,
        h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd
    }
}
>>> a = apply(lambda x: x.value * 7).x
>>> d >>= a
>>> d.show(colored=False)
{
    x: λ(x=21),
    h: {
        a: 2,
        _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
        _ids: {
            a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
        }
    },
    _id: okwLxwrcv9.FCsOTgCrB0ZG0yBArMbEaeqXNIGa7,
    _ids: {
        x: H8Tgrs3lS78y7Nqm0Qaaks8JLygevb49SEOpn5QD,
        h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd
    }
}
>>> a = apply(lambda x: x.value * 7, entry("x")).x
>>> d >>= a
>>> d.show(colored=False)
{
    x: λ(λ(x=21)),
    h: {
        a: 2,
        _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
        _ids: {
            a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
        }
    },
    _id: ZAozaV7y5Z1cjwzR9XoiBggegMtt9VC-Leafzaod,
    _ids: {
        x: Hqq4pKtqmIAejPzyjEf6BixYtzWYVU2Znp1TdB1K,
        h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd
    }
}
>>> d >>= {"b" : 2, "c": entry("b")}
>>> d.show(colored=False)
{
    x: λ(λ(x=21)),
    h: {
        a: 2,
        _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
        _ids: {
            a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
        }
    },
    b: 2,
    c: ·2,
    _id: 9bTAxQR8bR-XsqVTjc7sLgCvTXoJCWXwRS6pNLHe,
    _ids: {
        x: Hqq4pKtqmIAejPzyjEf6BixYtzWYVU2Znp1TdB1K,
        h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
        b: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29,
        c: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
    }
}
>>> d >>= {"b" : (2, 3), ("a1", "b1"): [0, 1]}
>>> d >>= {("a2", "b2"): _.b}
>>> d >>= {("a3", "b3"): entry("b")}
>>> d.show(colored=False)  # todo: : improve output for subvalues (and backtracking in general for pointer-like entries)
{
    x: λ(λ(x=21)),
    h: {
        a: 2,
        _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
        _ids: {
            a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
        }
    },
    b: [
        2,
        3
    ],
    c: ·2,
    a1: 0,
    b1: 1,
    a2: "(2, 3)→0",
    b2: "(2, 3)→1",
    a3: ·(2, 3)→0,
    b3: ·(2, 3)→1,
    _id: gf.QcPTyypNvMcSEMveLdLVC2T218MgepHPb9Md4,
    _ids: {
        x: Hqq4pKtqmIAejPzyjEf6BixYtzWYVU2Znp1TdB1K,
        h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
        b: -a.WUGANQp6aVgbRCtUljlgs12HNtJ-dJOAgSZWk,
        c: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29,
        a1: M7HyZUgSF.ZSmBEMFcDkiZBQz00wU9pGF3DoRiDu,
        b1: DYu5bfVvb6FOhBCWNsss4wsEWHZYTbKnsVgoWFvl,
        a2: GfnITQ6RdDtm4F-F0UuU8fOJX1DZIBZG5RWBM8wm,
        b2: QznFPbiCaMRZKUoFhdLxMKYQf3ujIe1zDl9G5Rq-,
        a3: GfnITQ6RdDtm4F-F0UuU8fOJX1DZIBZG5RWBM8wm,
        b3: QznFPbiCaMRZKUoFhdLxMKYQf3ujIe1zDl9G5Rq-
    }
}
Expand source code
class apply(AbsBaseArgument):
    """
    Function application

    Single output application is defined by attribute: 'apply(f).my_output_field'.
    Multioutput application is defined by a call: 'apply(f)("output_field1", "output_field2")'.

    >>> from hdict import apply, value, frozenhdict, _
    >>> f = lambda a, b: a**b
    >>> v = apply(f, 5, b=7)
    >>> v
    λ(5 7)
    >>> g = lambda x, y: x**y
    >>> apply(g, y=value(7777), x=v)
    λ(x=λ(5 7) 7777)

    >>> v2 = apply(f, a=v, b=value(7))
    >>> v2
    λ(a=λ(5 7) 7)
    >>> v.enclosure({}, "j", None).value
    78125
    >>> v2.enclosure({}, "j", None)
    λ(a=λ(5 7) 7)
    >>> v2.enclosure({}, "j", None).value
    17763568394002504646778106689453125

    >>> f = lambda a,b, c=1,d=2,e=13: 0
    >>> apply(f).requirements
    {'a': field(a), 'b': field(b), 'c': default(1), 'd': default(2), 'e': default(13)}
    >>> ap = apply(f,3)
    >>> ap.requirements
    {'a': 3, 'b': field(b), 'c': default(1), 'd': default(2), 'e': default(13)}
    >>> ap
    λ(3 b c=default(1) d=default(2) e=default(13))
    >>> ap.enclosure({"b": value(77)}, "j", None)
    λ(3 b c=1 d=2 e=13)
    >>> ap
    λ(3 b c=default(1) d=default(2) e=default(13))
    >>> d = {"f": ap, "b": 5, "d": 1, "e": field("b")}
    >>> d
    {'f': λ(3 b c=default(1) d=default(2) e=default(13)), 'b': 5, 'd': 1, 'e': field(b)}
    >>> from hdict.data.aux_frozendict import handle_items
    >>> handle_items(d, previous=frozenhdict({"b": 5}))
    {'b': 5, 'f': λ(3 b c=1 d=2 e=13), 'd': 1, 'e': 5}
    >>> d
    {'f': λ(3 b c=default(1) d=default(2) e=default(13)), 'b': 5, 'd': 1, 'e': field(b)}
    >>> apply(f,3,4).requirements
    {'a': 3, 'b': 4, 'c': default(1), 'd': default(2), 'e': default(13)}
    >>> apply(f,3,4,5).requirements
    {'a': 3, 'b': 4, 'c': 5, 'd': default(2), 'e': default(13)}
    >>> apply(f,3,4,5,6).requirements
    {'a': 3, 'b': 4, 'c': 5, 'd': 6, 'e': default(13)}
    >>> apply(f,3,4,5,6,7).requirements
    {'a': 3, 'b': 4, 'c': 5, 'd': 6, 'e': 7}
    >>> apply(f,d=5).requirements
    {'a': field(a), 'b': field(b), 'c': default(1), 'd': 5, 'e': default(13)}
    >>> f = lambda a,b, *arg, c=1,d=2,e=13, **kwargs: 0
    >>> apply(f,3,4,5,6,7,8).requirements
    {'a': 3, 'b': 4, arg_2: 5, arg_3: 6, arg_4: 7, arg_5: 8, 'c': default(1), 'd': default(2), 'e': default(13)}
    >>> apply(f,x=3,e=4,d=5,c=6,b=7,a=8).requirements
    {'a': 8, 'b': 7, 'c': 6, 'd': 5, 'e': 4, 'x': 3}
    >>> apply(f,3,c=77,x=5).requirements
    {'a': 3, 'b': field(b), 'c': 77, 'd': default(2), 'e': default(13), 'x': 5}
    >>> apply(f,b=77,x=5).requirements
    {'a': field(a), 'b': 77, 'c': default(1), 'd': default(2), 'e': default(13), 'x': 5}
    >>> from hdict.content.argument.entry import entry
    >>> a = apply(lambda x: x.value * 7, x=entry("x"))
    >>> c = {"x": 3, "y": entry("x")} >> a.r
    >>> c.show(colored=False)
    {
        x: 3,
        y: ·3,
        r: λ(·x),
        _id: bh0bgTZI.2f-WteZFpIrsMxJvZYUBydOfF3wFLV.,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            r: NoAit6.-dyFNiCZnoRAhY5zbJ0hc6u5lkQzYwBCx
        }
    }
    >>> b = a.x.sample()
    >>> b
    x=λ(·x)
    >>> d = {"x": 3} >> b
    >>> d.x
    21
    >>> a.sampleable
    False
    >>> a.sample()
    λ(·x)
    >>> d["h"] = frozenhdict(a=2)
    >>> d.show(colored=False)
    {
        x: 21,
        h: {
            a: 2,
            _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
            _ids: {
                a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
            }
        },
        _id: V8nyMrJbhGschQAaW3ZXD6uxvVRIluFmIFIkSaZ0,
        _ids: {
            x: NoAit6.-dyFNiCZnoRAhY5zbJ0hc6u5lkQzYwBCx,
            h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd
        }
    }
    >>> a = apply(lambda x: x.value * 7).x
    >>> d >>= a
    >>> d.show(colored=False)
    {
        x: λ(x=21),
        h: {
            a: 2,
            _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
            _ids: {
                a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
            }
        },
        _id: okwLxwrcv9.FCsOTgCrB0ZG0yBArMbEaeqXNIGa7,
        _ids: {
            x: H8Tgrs3lS78y7Nqm0Qaaks8JLygevb49SEOpn5QD,
            h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd
        }
    }
    >>> a = apply(lambda x: x.value * 7, entry("x")).x
    >>> d >>= a
    >>> d.show(colored=False)
    {
        x: λ(λ(x=21)),
        h: {
            a: 2,
            _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
            _ids: {
                a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
            }
        },
        _id: ZAozaV7y5Z1cjwzR9XoiBggegMtt9VC-Leafzaod,
        _ids: {
            x: Hqq4pKtqmIAejPzyjEf6BixYtzWYVU2Znp1TdB1K,
            h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd
        }
    }
    >>> d >>= {"b" : 2, "c": entry("b")}
    >>> d.show(colored=False)
    {
        x: λ(λ(x=21)),
        h: {
            a: 2,
            _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
            _ids: {
                a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
            }
        },
        b: 2,
        c: ·2,
        _id: 9bTAxQR8bR-XsqVTjc7sLgCvTXoJCWXwRS6pNLHe,
        _ids: {
            x: Hqq4pKtqmIAejPzyjEf6BixYtzWYVU2Znp1TdB1K,
            h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
            b: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29,
            c: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
        }
    }
    >>> d >>= {"b" : (2, 3), ("a1", "b1"): [0, 1]}
    >>> d >>= {("a2", "b2"): _.b}
    >>> d >>= {("a3", "b3"): entry("b")}
    >>> d.show(colored=False)  # todo: : improve output for subvalues (and backtracking in general for pointer-like entries)
    {
        x: λ(λ(x=21)),
        h: {
            a: 2,
            _id: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
            _ids: {
                a: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29
            }
        },
        b: [
            2,
            3
        ],
        c: ·2,
        a1: 0,
        b1: 1,
        a2: "(2, 3)→0",
        b2: "(2, 3)→1",
        a3: ·(2, 3)→0,
        b3: ·(2, 3)→1,
        _id: gf.QcPTyypNvMcSEMveLdLVC2T218MgepHPb9Md4,
        _ids: {
            x: Hqq4pKtqmIAejPzyjEf6BixYtzWYVU2Znp1TdB1K,
            h: GfMhwM5bo6OzIpngAf8Ruro6.QgOv2kb0nbj0mgd,
            b: -a.WUGANQp6aVgbRCtUljlgs12HNtJ-dJOAgSZWk,
            c: k3PWYRxIEc0lEvD1f6rbnk.36RAD5AyfROy1aT29,
            a1: M7HyZUgSF.ZSmBEMFcDkiZBQz00wU9pGF3DoRiDu,
            b1: DYu5bfVvb6FOhBCWNsss4wsEWHZYTbKnsVgoWFvl,
            a2: GfnITQ6RdDtm4F-F0UuU8fOJX1DZIBZG5RWBM8wm,
            b2: QznFPbiCaMRZKUoFhdLxMKYQf3ujIe1zDl9G5Rq-,
            a3: GfnITQ6RdDtm4F-F0UuU8fOJX1DZIBZG5RWBM8wm,
            b3: QznFPbiCaMRZKUoFhdLxMKYQf3ujIe1zDl9G5Rq-
        }
    }
    """

    _sampleable, isfield, _requirements = None, False, None

    def __init__(self, appliable: callable | apply | field, *applied_args, fhosh: Hosh = None, _sampleable=None, **applied_kwargs):
        from hdict.content.argument.aux_apply import handle_args

        self.appliable = appliable
        if isinstance(fhosh, str):  # pragma: no cover
            fhosh = Hosh.fromid(fhosh)

        if isinstance(appliable, apply):  # "clone" mode
            self.fhosh = fhosh or appliable.fhosh
            self.fargs, self.fkwargs = appliable.fargs.copy(), appliable.fkwargs.copy()
            self.isfield = appliable.isfield
            self._sampleable = appliable.sampleable if _sampleable is None else _sampleable
            self.appliable = appliable.appliable
        elif isinstance(appliable, field):
            # todo: : o que era isso mesmo?::  "function will be provided by hdict"-mode constrains 'applied_args'
            self.fhosh = fhosh
            self.fargs, self.fkwargs = handle_args(None, applied_args, applied_kwargs)
            self.isfield = True
            self._sampleable = _sampleable
        elif callable(appliable):
            if not (
                isfunction(appliable) or isbuiltin(appliable) or isclass(appliable)
            ):  # "not function" means "custom callable"; `builtin_function_or_method` is not a function and does not allow signature extraction.
                if not hasattr(appliable, "__call__"):  # pragma: no cover
                    raise Exception(f"Cannot infer method to apply non custom callable type '{type(appliable).__name__}'.")
                if not hasattr(appliable, "hosh"):  # pragma: no cover
                    raise Exception(f"Missing 'hosh' attribute while applying custom callable class '{type(appliable).__name__}'")
                # noinspection PyUnresolvedReferences
                sig = signature(appliable.__call__)
                # noinspection PyUnresolvedReferences
                self.fhosh = fhosh or appliable.hosh
            else:
                self.fhosh = f2hosh(appliable) if fhosh is None else fhosh
                s = str(appliable)
                if s.startswith("<built-in function"):
                    if s.endswith("getattr>"):
                        self.appliable = appliable = getattr_
                sig = signature(appliable)

            # Separate positional parameters from named parameters looking at 'f' signature.
            self.fargs, self.fkwargs = handle_args(sig, applied_args, applied_kwargs)
            self._sampleable = _sampleable
        else:  # pragma: no cover
            raise Exception(f"Cannot apply type '{type(appliable).__name__}'.")

    @property
    def sampleable(self):
        if self._sampleable is None:
            gen = (req.sampleable for req in self.fargs.values())
            kwgen = (req.sampleable for req in self.fkwargs.values())
            self._sampleable = any(gen) or any(kwgen)
        return self._sampleable

    @property
    def ahosh(self):
        return self.fhosh.rev  # 'f' identified as an appliable function

    def clone(self, _sampleable=None):
        return apply(self, _sampleable=_sampleable)

    def sample(self, rnd: int | Random = None):
        if not self.sampleable:
            return self
        clone = self.clone(_sampleable=False)
        for k, v in clone.fargs.items():
            clone.fargs[k] = v.sample(rnd)
        for k, v in clone.fkwargs.items():
            clone.fkwargs[k] = v.sample(rnd)
        return clone

    def enclosure(self, data, key, previous):
        from hdict.content.entry.closure import Closure

        return Closure(self, data, [key], previous)

    def __call__(self, *out, **kwout):
        from hdict.expression.step.applyout import ApplyOut

        if not (out or kwout):  # pragma: no cover
            raise Exception(f"At least one output field must be specified to apply.")

        if out and kwout:  # pragma: no cover
            raise Exception(f"Cannot mix translated (**kwargs) and non translated (*args) outputs.")
        if len(out) == 1:
            out = out[0]
        return ApplyOut(self, out or tuple(kwout.items()))

    def __getattr__(self, item):
        # REMINDER: Work around getattribute missing all properties.
        if item not in ["ahosh", "requirements", "hosh"]:
            from hdict.expression.step.applyout import ApplyOut

            return ApplyOut(self, item)
        return self.__getattribute__(item)  # pragma: no cover

    def __rshift__(self, other):  # pragma: no cover
        raise Exception(f"Cannot pipeline an application before specifying the output field.")

    def __rrshift__(self, other):  # pragma: no cover
        raise Exception(f"Cannot apply before specifying the output field.")

    def __mul__(self, other):  # pragma: no cover
        raise Exception(f"Cannot pipeline an application before specifying the output field.")

    def __rmul__(self, other):  # pragma: no cover
        raise Exception(f"Cannot apply before specifying the output field.")

    def __repr__(self):
        from hdict.content.value import value
        from hdict.content.argument.entry import entry

        lst = []
        for param, content in sorted(chain(self.fargs.items(), self.fkwargs.items())):
            match content:
                case field(name=param):
                    lst.append(f"{param}")
                case entry(name=param):
                    lst.append(repr(content))
                case value():
                    lst.append(truncate(repr(content), width=7))
                case AbsArgument():
                    lst.append(f"{param}={repr(content)}")
                case _:  # pragma: no cover
                    raise Exception(f"Canoot repr `{type(content)}")
        return f"λ({' '.join(lst)})"

    @property
    def requirements(self):
        if self._requirements is None:
            self._requirements = {k: v for k, v in sorted(chain(self.fargs.items(), self.fkwargs.items()))}
        return self._requirements

Ancestors

Class variables

var isfield

Instance variables

var ahosh
Expand source code
@property
def ahosh(self):
    return self.fhosh.rev  # 'f' identified as an appliable function
var requirements
Expand source code
@property
def requirements(self):
    if self._requirements is None:
        self._requirements = {k: v for k, v in sorted(chain(self.fargs.items(), self.fkwargs.items()))}
    return self._requirements
var sampleable

bool(x) -> bool

Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.

Expand source code
@property
def sampleable(self):
    if self._sampleable is None:
        gen = (req.sampleable for req in self.fargs.values())
        kwgen = (req.sampleable for req in self.fkwargs.values())
        self._sampleable = any(gen) or any(kwgen)
    return self._sampleable

Methods

def clone(self)
Expand source code
def clone(self, _sampleable=None):
    return apply(self, _sampleable=_sampleable)
def enclosure(self, data, key, previous)
Expand source code
def enclosure(self, data, key, previous):
    from hdict.content.entry.closure import Closure

    return Closure(self, data, [key], previous)
def sample(self, rnd: int | Random = None)
Expand source code
def sample(self, rnd: int | Random = None):
    if not self.sampleable:
        return self
    clone = self.clone(_sampleable=False)
    for k, v in clone.fargs.items():
        clone.fargs[k] = v.sample(rnd)
    for k, v in clone.fkwargs.items():
        clone.fkwargs[k] = v.sample(rnd)
    return clone
class cache (storage: dict, *fields)
>>> from hdict import _, hdict, cache, apply
>>> storage = {}
>>> d = hdict(x=3, y=5) >> apply(lambda x, y: x / y).z
>>> d.show(colored=False)
{
    x: 3,
    y: 5,
    z: λ(x y),
    _id: IIh20mb2BGUx9XMCDwzTr4y7v-JaGin3eEHvx692,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        z: GC-BMZNVRagHxgUynUadKUYA1kZ8GzcUj6OKWstQ
    }
}
>>> d >>= cache(storage)
>>> d.show(colored=False)
{
    x: 3,
    y: 5,
    z: ↑↓ cached at <code>dict</code>·,
    _id: IIh20mb2BGUx9XMCDwzTr4y7v-JaGin3eEHvx692,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        z: GC-BMZNVRagHxgUynUadKUYA1kZ8GzcUj6OKWstQ
    }
}
>>> d.evaluate()
>>> d.show(colored=False)
{
    x: 3,
    y: 5,
    z: 0.6,
    _id: IIh20mb2BGUx9XMCDwzTr4y7v-JaGin3eEHvx692,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        z: GC-BMZNVRagHxgUynUadKUYA1kZ8GzcUj6OKWstQ
    }
}
Expand source code
class cache(AbsStep):
    """
    >>> from hdict import _, hdict, cache, apply
    >>> storage = {}
    >>> d = hdict(x=3, y=5) >> apply(lambda x, y: x / y).z
    >>> d.show(colored=False)
    {
        x: 3,
        y: 5,
        z: λ(x y),
        _id: IIh20mb2BGUx9XMCDwzTr4y7v-JaGin3eEHvx692,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            z: GC-BMZNVRagHxgUynUadKUYA1kZ8GzcUj6OKWstQ
        }
    }
    >>> d >>= cache(storage)
    >>> d.show(colored=False)
    {
        x: 3,
        y: 5,
        z: ↑↓ cached at `dict`·,
        _id: IIh20mb2BGUx9XMCDwzTr4y7v-JaGin3eEHvx692,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            z: GC-BMZNVRagHxgUynUadKUYA1kZ8GzcUj6OKWstQ
        }
    }
    >>> d.evaluate()
    >>> d.show(colored=False)
    {
        x: 3,
        y: 5,
        z: 0.6,
        _id: IIh20mb2BGUx9XMCDwzTr4y7v-JaGin3eEHvx692,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            z: GC-BMZNVRagHxgUynUadKUYA1kZ8GzcUj6OKWstQ
        }
    }
    """

    def __init__(self, storage: dict, *fields):
        self.storage = storage
        self.fields = fields

    def __repr__(self):
        return f"↑↓`{type(self.storage).__name__}`"

Ancestors

class field (name: str)

Pointer to a field, without knowing the concrete value yet

>>> from hdict import Ø, _, apply
>>> d = Ø
>>> d.show(colored=False)
{
    _id: 0000000000000000000000000000000000000000,
    _ids: {}
}
>>> d = +_
>>> d.show(colored=False)
{
    _id: 0000000000000000000000000000000000000000,
    _ids: {}
}
>>> d >>= {"x": 3, "y": 5} >> apply(lambda x, y: x + y).z
>>> d.show(colored=False)
{
    x: 3,
    y: 5,
    z: λ(x y),
    _id: ..SSoOQF.FYZDUevP1CGj0DJVc.M8cgimN70yI3C,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        z: 3j029VhuvENAnBK6JLRGl8ePpsQybm57sXKfX2oo
    }
}
>>> d >>= {"x": 3, "y": 5} >> apply(lambda x, y: x + y).x
>>> d.x
8
>>> d["x"] = apply(lambda x, y: x + y)
>>> d.x
13
Expand source code
@dataclass
class field(AbsBaseArgument):
    """
    Pointer to a field, without knowing the concrete value yet

    >>> from hdict import Ø, _, apply
    >>> d = Ø
    >>> d.show(colored=False)
    {
        _id: 0000000000000000000000000000000000000000,
        _ids: {}
    }
    >>> d = +_
    >>> d.show(colored=False)
    {
        _id: 0000000000000000000000000000000000000000,
        _ids: {}
    }
    >>> d >>= {"x": 3, "y": 5} >> apply(lambda x, y: x + y).z
    >>> d.show(colored=False)
    {
        x: 3,
        y: 5,
        z: λ(x y),
        _id: ..SSoOQF.FYZDUevP1CGj0DJVc.M8cgimN70yI3C,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            z: 3j029VhuvENAnBK6JLRGl8ePpsQybm57sXKfX2oo
        }
    }
    >>> d >>= {"x": 3, "y": 5} >> apply(lambda x, y: x + y).x
    >>> d.x
    8
    >>> d["x"] = apply(lambda x, y: x + y)
    >>> d.x
    13
    """

    name: str

    def __repr__(self):
        return f"field({self.name})"

Ancestors

Class variables

var name : str
class frozenhdict (**kwargs)

Immutable hdict.

Any nested 'hdict' value will be frozen to avoid inconsistency between the hdict id (inner id) and the frozenhdict id (outer id).

>>> from hdict import frozenhdict, hdict
>>> d = frozenhdict({"x": 3}, y=5)
>>> from hosh._internals_appearance import decolorize
>>> print(decolorize(repr(d)))  # This is equivalent to just 'd', without colors.
{
    x: 3,
    y: 5,
    _id: r5A2Mh6vRRO5rxi5nfXv1myeguGSTmqHuHev38qM,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2
    }
}
>>> bool(d), bool(frozenhdict())
(True, False)
>>> d.data
{'x': 3, 'y': 5}
>>> from hdict import _, apply
>>> d *= apply(lambda v, x: v - x).z
>>> str(d)
'⦑{x: 3, y: 5} » z=λ(v x)⦒'
>>> d.show(colored=False)
⦑{
    x: 3,
    y: 5,
    _id: r5A2Mh6vRRO5rxi5nfXv1myeguGSTmqHuHev38qM,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2
    }
} » z=λ(v x)⦒
>>> d = {"v": 7} * d
>>> d.solve().show(colored=False)
{
    v: 7,
    x: 3,
    y: 5,
    z: λ(v x),
    _id: 0qFPOnULZigyiXU9Jv.1D.XSTIYHZ24UCT00DMHF,
    _ids: {
        v: eJCW9jGsdZTD6-AD9opKwjPIOWZ4R.T0CG2kdyzf,
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        z: 2-wfv1b9RyFHB2kdba3EBCy6Do5L-mMPJjT-nfPa
    }
}
>>> d = _ >> d
>>> d.show(colored=False)
{
    v: 7,
    x: 3,
    y: 5,
    z: λ(v x),
    _id: 0qFPOnULZigyiXU9Jv.1D.XSTIYHZ24UCT00DMHF,
    _ids: {
        v: eJCW9jGsdZTD6-AD9opKwjPIOWZ4R.T0CG2kdyzf,
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        z: 2-wfv1b9RyFHB2kdba3EBCy6Do5L-mMPJjT-nfPa
    }
}
>>> d = {"a": 5} >> d
>>> d.show(colored=False)
{
    a: 5,
    v: 7,
    x: 3,
    y: 5,
    z: λ(v x),
    _id: jZrJ2CiVUA9OqW.G7dwb3KoaTWGMUmSUVUXn0CkM,
    _ids: {
        a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        v: eJCW9jGsdZTD6-AD9opKwjPIOWZ4R.T0CG2kdyzf,
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        z: 2-wfv1b9RyFHB2kdba3EBCy6Do5L-mMPJjT-nfPa
    }
}
>>> from hdict.content.entry import AbsEntry, Unevaluated
>>> from hdict import frozenhdict
Expand source code
class frozenhdict(UserDict, dict[str, VT]):
    """
    Immutable hdict.

    Any nested 'hdict' value will be frozen to avoid inconsistency between the hdict id (inner id) and the frozenhdict id (outer id).

    >>> from hdict import frozenhdict, hdict
    >>> d = frozenhdict({"x": 3}, y=5)
    >>> from hosh._internals_appearance import decolorize
    >>> print(decolorize(repr(d)))  # This is equivalent to just 'd', without colors.
    {
        x: 3,
        y: 5,
        _id: r5A2Mh6vRRO5rxi5nfXv1myeguGSTmqHuHev38qM,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2
        }
    }
    >>> bool(d), bool(frozenhdict())
    (True, False)
    >>> d.data
    {'x': 3, 'y': 5}
    >>> from hdict import _, apply
    >>> d *= apply(lambda v, x: v - x).z
    >>> str(d)
    '⦑{x: 3, y: 5} » z=λ(v x)⦒'
    >>> d.show(colored=False)
    ⦑{
        x: 3,
        y: 5,
        _id: r5A2Mh6vRRO5rxi5nfXv1myeguGSTmqHuHev38qM,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2
        }
    } » z=λ(v x)⦒
    >>> d = {"v": 7} * d
    >>> d.solve().show(colored=False)
    {
        v: 7,
        x: 3,
        y: 5,
        z: λ(v x),
        _id: 0qFPOnULZigyiXU9Jv.1D.XSTIYHZ24UCT00DMHF,
        _ids: {
            v: eJCW9jGsdZTD6-AD9opKwjPIOWZ4R.T0CG2kdyzf,
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            z: 2-wfv1b9RyFHB2kdba3EBCy6Do5L-mMPJjT-nfPa
        }
    }
    >>> d = _ >> d
    >>> d.show(colored=False)
    {
        v: 7,
        x: 3,
        y: 5,
        z: λ(v x),
        _id: 0qFPOnULZigyiXU9Jv.1D.XSTIYHZ24UCT00DMHF,
        _ids: {
            v: eJCW9jGsdZTD6-AD9opKwjPIOWZ4R.T0CG2kdyzf,
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            z: 2-wfv1b9RyFHB2kdba3EBCy6Do5L-mMPJjT-nfPa
        }
    }
    >>> d = {"a": 5} >> d
    >>> d.show(colored=False)
    {
        a: 5,
        v: 7,
        x: 3,
        y: 5,
        z: λ(v x),
        _id: jZrJ2CiVUA9OqW.G7dwb3KoaTWGMUmSUVUXn0CkM,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            v: eJCW9jGsdZTD6-AD9opKwjPIOWZ4R.T0CG2kdyzf,
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            z: 2-wfv1b9RyFHB2kdba3EBCy6Do5L-mMPJjT-nfPa
        }
    }
    >>> from hdict.content.entry import AbsEntry, Unevaluated
    >>> from hdict import frozenhdict
    """

    _evaluated = None
    _asdict, _asdicts, _asdicts_noid = None, None, None
    _hoshes = None

    # noinspection PyMissingConstructor
    def __init__(self, /, _dictionary=None, _previous=None, **kwargs):
        from hdict.content.entry import AbsEntry
        from hdict.data.aux_frozendict import handle_identity
        from hdict.data.aux_frozendict import handle_items

        # todo: : check if _dictionary keys is 'str'; regex to check if k is an identifier;
        data = _dictionary or {}
        # REMINDER: Inside data, the only 'dict' entries are "_id" and "_ids", the rest are AbsEntry objects.
        self.data: dict[str, AbsEntry | str | dict[str, str]]
        self.data = handle_items(data, kwargs, previous=_previous)
        self.hosh, self.ids = handle_identity(self.data)
        self.id = self.hosh.id
        self.raw = self.data

    @property
    def hoshes(self):
        if self._hoshes is None:
            self._hoshes = {k: v.hosh for k, v in self.data.items()}
        return self._hoshes

    def __rmul__(self, left):
        from hdict import frozenhdict
        from hdict.expression.step.edict import EDict
        from hdict.expression.expr import Expr

        from hdict import hdict

        if isinstance(left, dict) and not isinstance(left, (hdict, frozenhdict)):
            return Expr(EDict(left), self)
        return NotImplemented  # pragma: no cover

    def __mul__(self, other):
        from hdict import hdict, frozenhdict
        from hdict.expression.step.edict import EDict
        from hdict.expression.expr import Expr
        from hdict.expression.step.step import AbsStep

        match other:
            case AbsStep() | hdict() | frozenhdict():
                return Expr(self, other)
            case dict():
                return Expr(self, EDict(other))
            case _:  # pragma: no cover
                return NotImplemented

    def __rrshift__(self, left):
        from hdict import hdict

        if isinstance(left, dict) and not isinstance(left, (hdict, frozenhdict)):
            return frozenhdict(left) >> self
        return NotImplemented  # pragma: no cover

    def __rshift__(self, other):
        # If merging, keep ids.
        from hdict import hdict
        from hdict.expression.step.applyout import ApplyOut
        from hdict.expression.step.cache import cache
        from hdict.content.entry.cached import Cached

        from hdict.content.argument.apply import apply

        if isinstance(other, apply):  # pragma: no cover
            raise Exception(f"Cannot apply without specifying output(s).\n" f"Hint: d >> apply(f)('output_field1', 'output_field2')")
        from hdict.content.argument import AbsArgument

        if isinstance(other, AbsArgument):  # pragma: no cover
            raise Exception(f"Cannot pipe {type(other).__name__} without specifying output.\n" "Hint: d >> {'field name': object}\n" f"Hint: d['field name'] = object")

        from hdict.expression.expr import Expr

        match other:
            case hdict() | frozenhdict():
                dct = other.raw
            case ApplyOut(nested, out):
                dct = {out: nested}
            case cache(storage=storage, fields=fields):
                if not fields:
                    fields = (k for k, v in self.raw.items() if not v.isevaluated)
                dct = {k: Cached(self.ids[k], storage, self.raw[k]) for k in fields}
            case dict():
                dct = other
            case Expr():
                return Expr(self, other).solve()
            case _:  # pragma: no cover
                return NotImplemented
        return frozenhdict(dct, _previous=self)

    def __getitem__(self, item):  # pragma: no cover
        return self.data[item].value

    def __getattr__(self, item):  # pragma: no cover
        if item in self.data:
            return self.data[item].value
        return self.__getattribute__(item)

    def __setitem__(self, key: str, value):  # pragma: no cover
        print(value)
        raise Exception(f"Cannot set an entry ({key}) of a frozen dict.")

    def __delitem__(self, key):  # pragma: no cover
        raise Exception(f"Cannot delete an entry ({key}) from a frozen dict.")

    @staticmethod
    def fromdict(dictionary, ids):
        """Build a frozenidict from values and pre-defined ids

        >>> from hdict import hdict, value
        >>> hdict.fromdict({"x": value(5, hosh="0123456789012345678901234567890123456789")}, {"x": "0123456789012345678901234567890123456789"}).show(colored=False)
        {
            x: 5,
            _id: bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq,
            _ids: {
                x: 0123456789012345678901234567890123456789
            }
        }
        """
        from hdict.content.value import value
        from hdict.content.entry import AbsEntry

        data = {}
        for k, v in dictionary.items():
            if isinstance(v, AbsEntry):
                if k in ids and ids[k] != v.id:  # pragma: no cover
                    raise Exception(f"Conflicting ids provided for key '{k}': ival.id={v.id}; ids[{k}]={ids[k]}")
                data[k] = v
            else:
                data[k] = value(v, ids[k] if k in ids else None)
        return frozenhdict(data)

    @property
    def evaluated(self):
        if self._evaluated is None:
            for k, val in self.data.items():
                val.evaluate()
            self._evaluated = self
        return self

    def evaluate(self):
        # todo: add flag to inhibit evaluation (i.e., fetching) of cached values; or other solution, e.g. Cache(write_onapply)
        _ = self.evaluated

    @property
    def asdict(self):
        """
        Convert to 'dict', including ids.

        This evaluates all fields.
        HINT: Use 'dict(d)' to convert a 'hdict' to a 'dict' excluding ids.

        >>> from hdict import hdict, value
        >>> d = hdict.fromdict({"x": value(5, hosh="0123456789012345678901234567890123456789")}, {"x": "0123456789012345678901234567890123456789"})
        >>> d.asdict
        {'x': 5, '_id': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq', '_ids': {'x': '0123456789012345678901234567890123456789'}}
        """
        if self._asdict is None:
            dic = dict(self.items())
            dic["_id"] = self.id
            dic["_ids"] = self.ids.copy()
            self._asdict = dic
        return self._asdict

    @property
    def asdicts(self):
        """
        Convert to 'dict' recursing into nested frozenhdicts, including ids.

        This evaluates all fields.
        REMINDER: hdict is never nested, frozenhdict is used instead
        HINT: Use 'asdicts_noid' to recursively convert a 'hdict' to a 'dict' excluding ids.

        >>> from hdict import value, hdict
        >>> d = hdict(x=value(5, hosh="0123456789012345678901234567890123456789"))
        >>> e = hdict(d=d)
        >>> e.asdicts
        {'d': {'x': 5, '_id': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq', '_ids': {'x': '0123456789012345678901234567890123456789'}}, '_id': 'GGhKhUmGhISaoHevn39hb-pLZEMoAc3KzE6Z0.IH', '_ids': {'d': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq'}}
        >>> dict(e) == e
        True
        """
        if self._asdicts is None:
            from hdict import hdict

            dic = {}
            for k, v in self.items():
                dic[k] = v.asdicts if isinstance(v, (hdict, frozenhdict)) else v
            dic["_id"] = self.id
            dic["_ids"] = self.ids.copy()
            self._asdicts = dic
        return self._asdicts

    @property
    def asdicts_noid(self):
        """
        Convert to 'dict' recursing into nested frozenhdicts, excluding ids.

        REMINDER: hdict is never nested, frozenhdict is used instead
        HINT: Use 'asdicts' to recursively convert a 'hdict' 'd' to 'dict' including ids.

        >>> from hdict import value, hdict
        >>> d = hdict(x=value(5, hosh="0123456789012345678901234567890123456789"))
        >>> e = hdict(d=d)
        >>> e.asdicts_noid
        {'d': {'x': 5}}
        >>> dict(e) == e
        True

        """
        if self._asdicts_noid is None:
            from hdict import hdict

            dic = {}
            for k, v in self.items():
                dic[k] = v.asdicts_noid if isinstance(v, (hdict, frozenhdict)) else v
            self._asdicts_noid = dic
        return self._asdicts_noid

    @property
    def asdicts_hoshes_noneval(self):
        from hdict import value
        from hdict.content.entry import AbsEntry

        hoshes = set()
        dic = {}
        for k, val in self.data.items():
            if isinstance(val, AbsEntry):
                hoshes.add(val.hosh)
            if isinstance(val, value):
                v = val.value
                if isinstance(v, frozenhdict):
                    dic[k], subhoshes = v.asdicts_hoshes_noneval
                    hoshes.update(subhoshes)
                else:
                    dic[k] = v
            else:
                dic[k] = val
        hoshes.add(self.hosh)
        dic["_id"] = self.id
        dic["_ids"] = self.ids.copy()
        return dic, hoshes

    def astext(self, colored=True, key_quotes=False):
        r"""Textual representation of a frozenidict object"""
        dicts, hoshes = self.asdicts_hoshes_noneval
        txt = json.dumps(dicts, indent=4, ensure_ascii=False, cls=CustomJSONEncoder)

        # Put colors after json, to avoid escaping ansi codes.  todo: check how HTML behaves here
        for h in hoshes:
            txt = txt.replace(f'"{h.id}"', repr(h)) if colored else txt.replace(f'"{h.id}"', h.id)

        # Remove quotes.
        txt = re.sub(r'(": )"(λ.+?)"(?=,\n)', '": \\2', txt)  # Closure
        txt = re.sub(r'(": )"(·.+?)"(?=,\n)', '": \\2', txt)  # Wrapper
        txt = re.sub(r'(": )"(↑↓ cached at `.+?·)"(?=,\n)', '": \\2', txt)  # cache
        if not key_quotes:
            txt = re.sub(r'(?<!: )"([\-a-zA-Z0-9_ ]+?)"(?=: )', "\\1", txt)  # keys

        return txt

    def show(self, colored=True, key_quotes=False):
        r"""Print textual representation of a frozenidict object"""
        print(self.astext(colored, key_quotes))

    def copy(self):  # pragma: no cover
        raise Exception("A FrozenIdict doesn't need copies")

    @property
    def unfrozen(self):
        from hdict import hdict

        return hdict(_frozen=self)

    # def entries(self, evaluate=True):
    #     """Iterator over all items"""
    #     yield from self.items(evaluate)
    #     # yield from self.metaitems(evaluate)

    def keys(self):
        """Generator of keys which don't start with '_'"
        >>> from hdict import hdict
        >>> list(hdict(x=3, y=5).keys())
        ['x', 'y']
        >>> list(hdict(x=3, y=5).values())
        [3, 5]
        """
        # return (k for k in self.data if not k.startswith("_"))
        return self.data.keys()

    def values(self, evaluate=True):
        """Generator of field values (keys that don't start with '_')"""
        return ((v.value if evaluate else v) for k, v in self.data.items())
        # return ((v.value if evaluate else v) for k, v in self.data.items() if not k.startswith("_"))

    def items(self, evaluate=True):
        """Generator over field-value pairs"""
        for k, val in self.data.items():
            # if not k.startswith("_"):
            yield k, (val.value if evaluate else val)

    def save(self, storage: dict):
        """
        Store an entire frozenidict
        """
        from hdict.persistence.stored import Stored

        data = {self.id: self.ids}
        for field, fid in self.ids.items():
            value = self[field]
            if field.endswith("_"):
                raise Exception(f"Not implemented for mirror fields")
                # todo:  confirm existence of the counterpart
                # data[kindid(fid)] = str(type(value))
            elif isinstance(value, frozenhdict):
                value.save(storage)
            else:
                data[fid] = Stored(value)
        # todo:  check if frozenhdict is being stored by mistake
        # todo:  attribute/method as subfield:
        #       apply(f, _.df.x)            SubField(name="df", attribute="x")
        #       apply(_.df.drop, "col1")    SubField(name="df", attribute="drop")
        #
        storage.update(data)

    @staticmethod
    def load(id, storage: dict, lazy=True) -> Union["frozenhdict", None]:
        """
        Fetch an entire frozenidict
        """
        if len(id) != 40:  # pragma: no cover
            raise Exception(f"id should have lenght of 40, not {len(id)}")
        return frozenhdict.fetch(id, storage, lazy, ishdict=True)

    @staticmethod
    def fetch(id: str, storage: dict, lazy=True, ishdict=False) -> Union["frozenhdict", None]:
        """
        Fetch a single entry

        When cache is a list, traverse it from the end (right item to the left item).
        """
        from hdict.content.entry.cached import Cached
        from hdict.persistence.stored import Stored

        if id not in storage:
            return None
        obj = storage[id]
        if isinstance(obj, dict):
            ishdict = True  # Set to True, because now we have a nested frozenhdict
        elif ishdict or not isinstance(obj, Stored):  # pragma: no cover
            raise Exception(f"Wrong content for hdict expected under id {id}: {type(obj)}.")

        if ishdict:
            ids = obj
            data = {}
            mirrored = set()
            for field, fid in ids.items():
                if field.endswith("_"):
                    # TODO:  2023-06-23
                    #  -
                    raise Exception(f"Not implemented for mirror fields")
                    # mirrored.add(field[:-1])
                    continue
                if lazy:
                    data[field] = Cached(fid, storage)
                else:
                    obj = frozenhdict.fetch(fid, storage, lazy=False, ishdict=False)
                    if obj is None:  # pragma: no cover
                        print(storage.keys())
                        raise Exception(f"Incomplete hdict: id '{id}' not found in the provided cache.")
                    data[field] = obj
            # for field in mirrored:
            #     obj = data[field]
            #     kind = obj.kind if isinstance(obj, Cached) else getkind(storage, obj.hosh)
            #     data[field + "_"] = handle_mirror(field, data, ids[field], kind)
            return frozenhdict.fromdict(data, ids)

        return obj.content

    @property
    def asdf(self):
        """
        Represent hdict as a DataFrame if possible
        """
        from pandas import DataFrame

        data = dict(self)
        index = data.pop("index")
        return DataFrame(data, index=index)

    @staticmethod
    def fromfile(name, fields=None, format="df", named=None, hide_types=True):
        r"""
        Input format is defined by file extension: .arff, .csv
        """
        from hdict.data.aux_frozendict import handle_format

        df, name = file2df(name, hide_types, True)
        return handle_format(format, fields, df, named and name)

    @staticmethod
    def fromtext(text: str, fields=None, format="df", named=None):
        r"""
        Input format is defined by file extension: .arff, .csv
        """
        from hdict import frozenhdict

        if text.startswith("@"):
            name = "<Unnamed>"
            with StringIO() as f:
                f.write(text)
                text = f.getvalue()
                df = loads(text)
                for line in isplit(text, "\n"):
                    if line[:9].upper() == "@RELATION":
                        name = line[9:].strip()
                        break
        else:
            from testfixtures import TempDirectory

            with TempDirectory() as tmp:
                tmp.write(
                    "temp.csv",
                    text.encode(),
                )
                return frozenhdict.fromfile(tmp.path + "/temp.csv", fields, format, named)

        from hdict.data.aux_frozendict import handle_format

        return handle_format(format, fields, df, named and name)

    def __eq__(self, other):
        if isinstance(other, dict):
            if "_id" in other:
                return self.id == other["_id"]
            if list(self.keys()) != list(other.keys()):
                return False
            from hdict import hdict

            if isinstance(other, (frozenhdict, hdict)):
                return self.id == other.id
            return dict(self) == other
        return NotImplemented  # pragma: no cover

    def __ne__(self, other):
        return not (self == other)

    def __repr__(self):
        return self.astext()

    def __str__(self):
        return stringfy(self.data)

    def __iter__(self):
        for k in self.data:
            yield k

    def __hash__(self):
        return hash(self.hosh)

    def __bool__(self):
        return bool(self.data)

    # def __reduce__(self):
    # dic = self.data.copy()
    # del dic["_id"]
    # del dic["_ids"]
    # return self.__class__, (dic,)

Ancestors

  • collections.UserDict
  • collections.abc.MutableMapping
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • builtins.dict

Subclasses

Static methods

def fetch(id: str, storage: dict, lazy=True, ishdict=False) ‑> Optional[frozenhdict]

Fetch a single entry

When cache is a list, traverse it from the end (right item to the left item).

Expand source code
@staticmethod
def fetch(id: str, storage: dict, lazy=True, ishdict=False) -> Union["frozenhdict", None]:
    """
    Fetch a single entry

    When cache is a list, traverse it from the end (right item to the left item).
    """
    from hdict.content.entry.cached import Cached
    from hdict.persistence.stored import Stored

    if id not in storage:
        return None
    obj = storage[id]
    if isinstance(obj, dict):
        ishdict = True  # Set to True, because now we have a nested frozenhdict
    elif ishdict or not isinstance(obj, Stored):  # pragma: no cover
        raise Exception(f"Wrong content for hdict expected under id {id}: {type(obj)}.")

    if ishdict:
        ids = obj
        data = {}
        mirrored = set()
        for field, fid in ids.items():
            if field.endswith("_"):
                # TODO:  2023-06-23
                #  -
                raise Exception(f"Not implemented for mirror fields")
                # mirrored.add(field[:-1])
                continue
            if lazy:
                data[field] = Cached(fid, storage)
            else:
                obj = frozenhdict.fetch(fid, storage, lazy=False, ishdict=False)
                if obj is None:  # pragma: no cover
                    print(storage.keys())
                    raise Exception(f"Incomplete hdict: id '{id}' not found in the provided cache.")
                data[field] = obj
        # for field in mirrored:
        #     obj = data[field]
        #     kind = obj.kind if isinstance(obj, Cached) else getkind(storage, obj.hosh)
        #     data[field + "_"] = handle_mirror(field, data, ids[field], kind)
        return frozenhdict.fromdict(data, ids)

    return obj.content
def fromdict(dictionary, ids)

Build a frozenidict from values and pre-defined ids

>>> from hdict import hdict, value
>>> hdict.fromdict({"x": value(5, hosh="0123456789012345678901234567890123456789")}, {"x": "0123456789012345678901234567890123456789"}).show(colored=False)
{
    x: 5,
    _id: bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq,
    _ids: {
        x: 0123456789012345678901234567890123456789
    }
}
Expand source code
@staticmethod
def fromdict(dictionary, ids):
    """Build a frozenidict from values and pre-defined ids

    >>> from hdict import hdict, value
    >>> hdict.fromdict({"x": value(5, hosh="0123456789012345678901234567890123456789")}, {"x": "0123456789012345678901234567890123456789"}).show(colored=False)
    {
        x: 5,
        _id: bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq,
        _ids: {
            x: 0123456789012345678901234567890123456789
        }
    }
    """
    from hdict.content.value import value
    from hdict.content.entry import AbsEntry

    data = {}
    for k, v in dictionary.items():
        if isinstance(v, AbsEntry):
            if k in ids and ids[k] != v.id:  # pragma: no cover
                raise Exception(f"Conflicting ids provided for key '{k}': ival.id={v.id}; ids[{k}]={ids[k]}")
            data[k] = v
        else:
            data[k] = value(v, ids[k] if k in ids else None)
    return frozenhdict(data)
def fromfile(name, fields=None, format='df', named=None, hide_types=True)

Input format is defined by file extension: .arff, .csv

Expand source code
@staticmethod
def fromfile(name, fields=None, format="df", named=None, hide_types=True):
    r"""
    Input format is defined by file extension: .arff, .csv
    """
    from hdict.data.aux_frozendict import handle_format

    df, name = file2df(name, hide_types, True)
    return handle_format(format, fields, df, named and name)
def fromtext(text: str, fields=None, format='df', named=None)

Input format is defined by file extension: .arff, .csv

Expand source code
@staticmethod
def fromtext(text: str, fields=None, format="df", named=None):
    r"""
    Input format is defined by file extension: .arff, .csv
    """
    from hdict import frozenhdict

    if text.startswith("@"):
        name = "<Unnamed>"
        with StringIO() as f:
            f.write(text)
            text = f.getvalue()
            df = loads(text)
            for line in isplit(text, "\n"):
                if line[:9].upper() == "@RELATION":
                    name = line[9:].strip()
                    break
    else:
        from testfixtures import TempDirectory

        with TempDirectory() as tmp:
            tmp.write(
                "temp.csv",
                text.encode(),
            )
            return frozenhdict.fromfile(tmp.path + "/temp.csv", fields, format, named)

    from hdict.data.aux_frozendict import handle_format

    return handle_format(format, fields, df, named and name)
def load(id, storage: dict, lazy=True) ‑> Optional[frozenhdict]

Fetch an entire frozenidict

Expand source code
@staticmethod
def load(id, storage: dict, lazy=True) -> Union["frozenhdict", None]:
    """
    Fetch an entire frozenidict
    """
    if len(id) != 40:  # pragma: no cover
        raise Exception(f"id should have lenght of 40, not {len(id)}")
    return frozenhdict.fetch(id, storage, lazy, ishdict=True)

Instance variables

var asdf

Represent hdict as a DataFrame if possible

Expand source code
@property
def asdf(self):
    """
    Represent hdict as a DataFrame if possible
    """
    from pandas import DataFrame

    data = dict(self)
    index = data.pop("index")
    return DataFrame(data, index=index)
var asdict

Convert to 'dict', including ids.

This evaluates all fields. HINT: Use 'dict(d)' to convert a 'hdict' to a 'dict' excluding ids.

>>> from hdict import hdict, value
>>> d = hdict.fromdict({"x": value(5, hosh="0123456789012345678901234567890123456789")}, {"x": "0123456789012345678901234567890123456789"})
>>> d.asdict
{'x': 5, '_id': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq', '_ids': {'x': '0123456789012345678901234567890123456789'}}
Expand source code
@property
def asdict(self):
    """
    Convert to 'dict', including ids.

    This evaluates all fields.
    HINT: Use 'dict(d)' to convert a 'hdict' to a 'dict' excluding ids.

    >>> from hdict import hdict, value
    >>> d = hdict.fromdict({"x": value(5, hosh="0123456789012345678901234567890123456789")}, {"x": "0123456789012345678901234567890123456789"})
    >>> d.asdict
    {'x': 5, '_id': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq', '_ids': {'x': '0123456789012345678901234567890123456789'}}
    """
    if self._asdict is None:
        dic = dict(self.items())
        dic["_id"] = self.id
        dic["_ids"] = self.ids.copy()
        self._asdict = dic
    return self._asdict
var asdicts

Convert to 'dict' recursing into nested frozenhdicts, including ids.

This evaluates all fields. REMINDER: hdict is never nested, frozenhdict is used instead HINT: Use 'asdicts_noid' to recursively convert a 'hdict' to a 'dict' excluding ids.

>>> from hdict import value, hdict
>>> d = hdict(x=value(5, hosh="0123456789012345678901234567890123456789"))
>>> e = hdict(d=d)
>>> e.asdicts
{'d': {'x': 5, '_id': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq', '_ids': {'x': '0123456789012345678901234567890123456789'}}, '_id': 'GGhKhUmGhISaoHevn39hb-pLZEMoAc3KzE6Z0.IH', '_ids': {'d': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq'}}
>>> dict(e) == e
True
Expand source code
@property
def asdicts(self):
    """
    Convert to 'dict' recursing into nested frozenhdicts, including ids.

    This evaluates all fields.
    REMINDER: hdict is never nested, frozenhdict is used instead
    HINT: Use 'asdicts_noid' to recursively convert a 'hdict' to a 'dict' excluding ids.

    >>> from hdict import value, hdict
    >>> d = hdict(x=value(5, hosh="0123456789012345678901234567890123456789"))
    >>> e = hdict(d=d)
    >>> e.asdicts
    {'d': {'x': 5, '_id': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq', '_ids': {'x': '0123456789012345678901234567890123456789'}}, '_id': 'GGhKhUmGhISaoHevn39hb-pLZEMoAc3KzE6Z0.IH', '_ids': {'d': 'bi5Qdbh-zgA1ZQdxGhxqjaKaQROtxk1VCPRZhMOq'}}
    >>> dict(e) == e
    True
    """
    if self._asdicts is None:
        from hdict import hdict

        dic = {}
        for k, v in self.items():
            dic[k] = v.asdicts if isinstance(v, (hdict, frozenhdict)) else v
        dic["_id"] = self.id
        dic["_ids"] = self.ids.copy()
        self._asdicts = dic
    return self._asdicts
var asdicts_hoshes_noneval
Expand source code
@property
def asdicts_hoshes_noneval(self):
    from hdict import value
    from hdict.content.entry import AbsEntry

    hoshes = set()
    dic = {}
    for k, val in self.data.items():
        if isinstance(val, AbsEntry):
            hoshes.add(val.hosh)
        if isinstance(val, value):
            v = val.value
            if isinstance(v, frozenhdict):
                dic[k], subhoshes = v.asdicts_hoshes_noneval
                hoshes.update(subhoshes)
            else:
                dic[k] = v
        else:
            dic[k] = val
    hoshes.add(self.hosh)
    dic["_id"] = self.id
    dic["_ids"] = self.ids.copy()
    return dic, hoshes
var asdicts_noid

Convert to 'dict' recursing into nested frozenhdicts, excluding ids.

REMINDER: hdict is never nested, frozenhdict is used instead HINT: Use 'asdicts' to recursively convert a 'hdict' 'd' to 'dict' including ids.

>>> from hdict import value, hdict
>>> d = hdict(x=value(5, hosh="0123456789012345678901234567890123456789"))
>>> e = hdict(d=d)
>>> e.asdicts_noid
{'d': {'x': 5}}
>>> dict(e) == e
True
Expand source code
@property
def asdicts_noid(self):
    """
    Convert to 'dict' recursing into nested frozenhdicts, excluding ids.

    REMINDER: hdict is never nested, frozenhdict is used instead
    HINT: Use 'asdicts' to recursively convert a 'hdict' 'd' to 'dict' including ids.

    >>> from hdict import value, hdict
    >>> d = hdict(x=value(5, hosh="0123456789012345678901234567890123456789"))
    >>> e = hdict(d=d)
    >>> e.asdicts_noid
    {'d': {'x': 5}}
    >>> dict(e) == e
    True

    """
    if self._asdicts_noid is None:
        from hdict import hdict

        dic = {}
        for k, v in self.items():
            dic[k] = v.asdicts_noid if isinstance(v, (hdict, frozenhdict)) else v
        self._asdicts_noid = dic
    return self._asdicts_noid
var evaluated
Expand source code
@property
def evaluated(self):
    if self._evaluated is None:
        for k, val in self.data.items():
            val.evaluate()
        self._evaluated = self
    return self
var hoshes
Expand source code
@property
def hoshes(self):
    if self._hoshes is None:
        self._hoshes = {k: v.hosh for k, v in self.data.items()}
    return self._hoshes
var unfrozen
Expand source code
@property
def unfrozen(self):
    from hdict import hdict

    return hdict(_frozen=self)

Methods

def astext(self, colored=True, key_quotes=False)

Textual representation of a frozenidict object

Expand source code
def astext(self, colored=True, key_quotes=False):
    r"""Textual representation of a frozenidict object"""
    dicts, hoshes = self.asdicts_hoshes_noneval
    txt = json.dumps(dicts, indent=4, ensure_ascii=False, cls=CustomJSONEncoder)

    # Put colors after json, to avoid escaping ansi codes.  todo: check how HTML behaves here
    for h in hoshes:
        txt = txt.replace(f'"{h.id}"', repr(h)) if colored else txt.replace(f'"{h.id}"', h.id)

    # Remove quotes.
    txt = re.sub(r'(": )"(λ.+?)"(?=,\n)', '": \\2', txt)  # Closure
    txt = re.sub(r'(": )"(·.+?)"(?=,\n)', '": \\2', txt)  # Wrapper
    txt = re.sub(r'(": )"(↑↓ cached at `.+?·)"(?=,\n)', '": \\2', txt)  # cache
    if not key_quotes:
        txt = re.sub(r'(?<!: )"([\-a-zA-Z0-9_ ]+?)"(?=: )', "\\1", txt)  # keys

    return txt
def copy(self)

D.copy() -> a shallow copy of D

Expand source code
def copy(self):  # pragma: no cover
    raise Exception("A FrozenIdict doesn't need copies")
def evaluate(self)
Expand source code
def evaluate(self):
    # todo: add flag to inhibit evaluation (i.e., fetching) of cached values; or other solution, e.g. Cache(write_onapply)
    _ = self.evaluated
def items(self, evaluate=True)

Generator over field-value pairs

Expand source code
def items(self, evaluate=True):
    """Generator over field-value pairs"""
    for k, val in self.data.items():
        # if not k.startswith("_"):
        yield k, (val.value if evaluate else val)
def keys(self)

Generator of keys which don't start with '_'"

>>> from hdict import hdict
>>> list(hdict(x=3, y=5).keys())
['x', 'y']
>>> list(hdict(x=3, y=5).values())
[3, 5]
Expand source code
def keys(self):
    """Generator of keys which don't start with '_'"
    >>> from hdict import hdict
    >>> list(hdict(x=3, y=5).keys())
    ['x', 'y']
    >>> list(hdict(x=3, y=5).values())
    [3, 5]
    """
    # return (k for k in self.data if not k.startswith("_"))
    return self.data.keys()
def save(self, storage: dict)

Store an entire frozenidict

Expand source code
def save(self, storage: dict):
    """
    Store an entire frozenidict
    """
    from hdict.persistence.stored import Stored

    data = {self.id: self.ids}
    for field, fid in self.ids.items():
        value = self[field]
        if field.endswith("_"):
            raise Exception(f"Not implemented for mirror fields")
            # todo:  confirm existence of the counterpart
            # data[kindid(fid)] = str(type(value))
        elif isinstance(value, frozenhdict):
            value.save(storage)
        else:
            data[fid] = Stored(value)
    # todo:  check if frozenhdict is being stored by mistake
    # todo:  attribute/method as subfield:
    #       apply(f, _.df.x)            SubField(name="df", attribute="x")
    #       apply(_.df.drop, "col1")    SubField(name="df", attribute="drop")
    #
    storage.update(data)
def show(self, colored=True, key_quotes=False)

Print textual representation of a frozenidict object

Expand source code
def show(self, colored=True, key_quotes=False):
    r"""Print textual representation of a frozenidict object"""
    print(self.astext(colored, key_quotes))
def values(self, evaluate=True)

Generator of field values (keys that don't start with '_')

Expand source code
def values(self, evaluate=True):
    """Generator of field values (keys that don't start with '_')"""
    return ((v.value if evaluate else v) for k, v in self.data.items())
    # return ((v.value if evaluate else v) for k, v in self.data.items() if not k.startswith("_"))
class hdict (**kwargs)

Function id is reversed before application. This is needed to enable handling a function as a value, under the original id.

>>> from hdict import hdict, apply, field
>>> from hdict.content.argument.default import default
>>> d = hdict({"x": 3}, y=5)
>>> d["alpha"] = 11
>>> d.show(colored=False)
{
    x: 3,
    y: 5,
    alpha: 11,
    _id: e6WGyTj7trk6AUUcdxGAefyG.T9j.SvBdEsHF.r5,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        alpha: A1RyW.GoA3q9-iCbCvWyWClExm1J3wI.ok6UA3Nk
    }
}
>>> d >>= {"beta": 12, "gamma": 17}
>>> d["p1", "q1"] = apply(lambda x, y=3: [x**y, x/y])
>>> d["pq"] = apply(lambda x, y=3: [x**y, x/y])
>>> d["p2", "q2"] = apply(lambda x=2, y=None: [x**y, x/y])
>>> f = lambda x, y: {"a": x**y, "b": x/y}
>>> d["z1", "w1"] = apply(f)
>>> d["z2":"a", "w2":"b"] = apply(f)
>>> d >>= {
...     "r1": apply(lambda x: x**2),
...     "r2": apply(lambda x: x**3),
...     "r3": apply(lambda x: x**4),
...     ("ra1", "rb1"): apply(f),
...     (("ra2", "a"), ("rb2", "b")): apply(f),
... }
>>> d["z2"]
243
>>> d["zz1", "ww1"] = apply(f, field("r1"), y=field("r2"))
>>> d >>= {("zz2", "ww2"): apply(f, y=field("r2"), x=9)}  # Define external value.
>>> d >>= {"zzzz": apply(f, y=13, x=9)}
>>> # Non-pickable custom classes need a custom 'hosh' attribute to be applied and also to be used as a value.
>>> from hosh import Hosh
>>> # Example of class that could be used as a value or as a function.
>>> from dataclasses import dataclass
>>> @dataclass
... class CustomClass:
...     hosh = Hosh.fromid("Some.arbitrary.identifier.with.length.40")
...     def __call__(self, x, y):
...         return x + y, x / y
>>> custom = CustomClass()
>>> d["f"] = custom  # Custom callable handled as a value.
>>> d["zzz1", "www1"] = apply(custom, 11, y=33)  # Custom callable being applied.
>>> d["zzz2", "www2"] = apply(field("f"), field("r1"), y=44)  # Callable field being applied.
>>> d.show(colored=False)
{
    x: 3,
    y: 5,
    alpha: 11,
    beta: 12,
    gamma: 17,
    p1: λ(x y)→0,
    q1: λ(x y)→1,
    pq: λ(x y),
    p2: λ(x y)→0,
    q2: λ(x y)→1,
    z1: λ(x y)→0,
    w1: λ(x y)→1,
    z2: 243,
    w2: λ(x y)→b,
    r1: λ(x),
    r2: λ(x),
    r3: λ(x),
    ra1: λ(x y)→0,
    rb1: λ(x y)→1,
    ra2: λ(x y)→a,
    rb2: λ(x y)→b,
    zz1: λ(x=r1 y=r2)→0,
    ww1: λ(x=r1 y=r2)→1,
    zz2: λ(9 y=r2)→0,
    ww2: λ(9 y=r2)→1,
    zzzz: λ(9 13),
    f: "CustomClass()",
    zzz1: λ(11 33)→0,
    www1: λ(11 33)→1,
    zzz2: λ(r1 44)→0,
    www2: λ(r1 44)→1,
    _id: i5wtTs5qggivS-y5TNuhnM5jwokjF132M7jF.49a,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        alpha: A1RyW.GoA3q9-iCbCvWyWClExm1J3wI.ok6UA3Nk,
        beta: WM5TbiaJ1gLqKRSFiY3VkZEu1PwQcaAokBKBPrWg,
        gamma: yb-HU.jSxd496XfId1J..MkX7xfUPJOL1-07hHdt,
        p1: Qs0J0I.AhR.brQjpYwUJqDNLk-zKd7FmG0g7gdd1,
        q1: VOAVwyrrdC7eIsjnVkqdpsqUfhprKzKriATFEOQI,
        pq: KtTWRcFQRKVgTJabGMgY-HAQWJ1TZGnOYw7NU.1K,
        p2: qb0H0MqNit0rLwk6CsC4Q2bxpCmBQ581eoGI39sr,
        q2: Sjsl-.MJJ3SK2.INLAJ-0R5BwlfG.tccIpxPFRtB,
        z1: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
        w1: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
        z2: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
        w2: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
        r1: FO3NXIQIi7TBFw1FqLRJYo13EA.uu4Y-L17Fmx0z,
        r2: HorxHsNCdpkm270yeTZ-vREjjFXWIYC99ALidDVU,
        r3: bWc33lXvXHIJXix5Jw2.Nhw0EIsv3TuAa7t8Ix5q,
        ra1: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
        rb1: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
        ra2: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
        rb2: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
        zz1: FB6W9j12qWZ34fUwyrBETzFuAXRB-xn7O1PGhr2j,
        ww1: IhchjkRfjLXpnsC6zl-TFugIQrnUIdB7Wsgpnely,
        zz2: LE5ohPby7q4dNu3qhqgucRcCt.pd87O.CyKWloqe,
        ww2: -RBf-UiccAG3sTH0UFC6C.YFmYcpTRA.0PFP6Oun,
        zzzz: Irbj-xVP8rEIPoylOTNmiuJ-lGdx0dpzIPgq-169,
        f: Some.arbitrary.identifier.with.length.40,
        zzz1: TBw0fUZZo1WlI9uczNuF0w4vC06u6YvzJyNPVEi1,
        www1: WqqXpIpMwinaXxYNqRjj4qttDcKXN.gcGjARpOSh,
        zzz2: .mJim0y-LMUYZi01GN8MTPkHj79JtFdREf7g40ug,
        www2: jwtsaf1IZMG6sWqprXZnc.n-ilyfncwhL3Qr.-Md
    }
}
>>> d["p1"]
243
>>> from hdict import value
>>> d.evaluate()
>>> d = hdict(x=2)
>>> g = lambda x, y: [x + y, x / y]
>>> d["z"] = apply(f, 2, y=3)
>>> d["w", "v"] = apply(f, field("x"), y=33)
>>> d["f"] = f
>>> d = d >> apply(field("f"), field("x"), y=default(3), nonexistent_parameter=7)("w3", "v3") # todo: : nonexistent parameter should raise an exception
>>> d >>= apply(field("f"), field("x"), y=default(3))("w", "v")
>>> d["w2", "v2"] = apply(field("f"), field("x"), y=default(3))
>>> d >>= {"z": apply(f, field("x"), y=3), ("w", "v"): apply(g, y=7)}
>>> d >>= apply(f, field("x"), y=3)("z9") * apply(g, y=7)("w9", "v9")
>>> pp = apply(f, field("x"), y=3)("z") >> apply(g, y=7)("w", "v")
>>> d >>= {"x": 3} >> pp >> apply(g, y=7)("w", "v")
>>> from hdict import _
>>> a1 = apply(f, y=_(1, 2, 4, ..., 128))
>>> a2 = apply(f, _(0, 3, 6, ..., 9), y=_(0, 3, 6, ..., 9))
>>> ppp = hdict() >> a2.sample()("k", "t")
>>> ppp.show(colored=False)
{
    k: λ(9 9)→0,
    t: λ(9 9)→1,
    _id: dK-iumb4L5nkFVT9LCkdk3daQtuC.ORk6JwWMhnt,
    _ids: {
        k: rHTgwW.w2SsbcvBlSnWWddLH4vgyXlM1Fhxqr48f,
        t: IldA8m-uSN9lJcE4TBtjTcY-sSiA33mzxQ2k-wpN
    }
}
>>> ppp.k
387420489
>>> a1("z")
z=λ(x y=~[1 2 .*. 128])
>>> a2(w="a", v="b")
(('w', 'a'), ('v', 'b'))=λ(x=~[0 3 .+. 9] y=~[0 3 .+. 9])
>>> p = a1("z") >> a2(w="a", v="b")
>>> h = lambda a, b=4: 5
>>> app = apply(h, a=_(0, 3, 6, ..., 9))
>>> app
λ(a=~[0 3 .+. 9] b=default(4))
>>> app.c
c=λ(a=~[0 3 .+. 9] b=default(4))
>>> sampled = app.sample(0).c
>>> sampled
c=λ(9 b=default(4))
>>> r = hdict() >> sampled
>>> r.show(colored=False)
{
    c: λ(9 b=4),
    _id: Bbe5mzn0oCuHZ.Y84-jaEnh3jcrgD8av6IZezKEG,
    _ids: {
        c: 6EehD7OoZe2REI.1YsVLKxSF4hJoYxfOZJLbF.Aj
    }
}
>>> r.evaluated.show(colored=False)
{
    c: 5,
    _id: Bbe5mzn0oCuHZ.Y84-jaEnh3jcrgD8av6IZezKEG,
    _ids: {
        c: 6EehD7OoZe2REI.1YsVLKxSF4hJoYxfOZJLbF.Aj
    }
}
>>> from random import Random
>>> rnd = Random(0)
>>> p1 = p.sample(rnd)
>>> d["w"]
10
>>> d >>= p1
>>> d["z"] = apply(f, 2, y=3)
>>> d["w", "v"] = apply(f, _.x, y=_.x)
>>> d["w", "v"] = apply(_.f, _.x, y=default(3))
>>> d = hdict() >> {"z": apply(f, 7, y=3), ("w", "v"): apply(g, default(6), y=7)}
>>> d = hdict(w=6) >> (apply(f, _["w"], y=3)(z="z") >> apply(g, x=_(1,2,3,...,5), y=7)("ww", "v")).sample(0)
>>> p = apply(f, y=_(1, 2, 4, ..., 128))("z") >> apply(f, y=_(0, 3, 6, ..., 9))(w="a", v="b")
>>> d.show(colored=False)
{
    w: 6,
    z: λ(x=w 3)→z,
    ww: λ(4 7)→0,
    v: λ(4 7)→1,
    _id: x4TxaVuAymsh97Yr.15Oc1ekllvlpECk091124RM,
    _ids: {
        w: CZ7Jm5fQMZ3fZJ3kAVOi0FYK-exFqPqgoYLsGxGl,
        z: No1nN40OXnJ.zOyAvoxwCjyD06cUDiXTZQh4q8xa,
        ww: qZepp.wpXCOYQrwnVIwoZ4kR9pIuMGDQpvRevv80,
        v: wxkjBSP54cKEfxKE1Zte-2dDll3G9Nd-yDh3CLas
    }
}
>>> d = hdict(x=3) >> p.sample(rnd)
>>> d.show(colored=False)
{
    x: 3,
    z: λ(x 16),
    w: λ(x 9)→a,
    v: λ(x 9)→b,
    _id: 22b-e.CtRGVSoMkektNzHYSVZTouhL2jAHLyPd4Q,
    _ids: {
        x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
        z: 64cxw0HmJ0fydH7By6i0HrbuwA759XexTu3Bu0Zd,
        w: p1Z5umNo12DHCZtKbh2EClW6TZxv.M447HlALWhv,
        v: HbYbR1RjPdU4jixjW7xSxslRpYx9W6Oiay7maK6F
    }
}
>>> d1 = hdict(x=52, y=13)
>>> d2 = hdict(x=value(52, hosh="1234567890123456789012345678901234567890"))
>>> d1.show(colored=False)
{
    x: 52,
    y: 13,
    _id: 5pwGP0LxQRbQaDEk9ztQ4V4qz.A-IIhVNTrcyt8U,
    _ids: {
        x: c.llz05T6ZXw5AlsU4xfmMxcvvHZhLl60LckZis9,
        y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
    }
}
>>> d2.show(colored=False)
{
    x: 52,
    _id: kYzgpPdRgQSYSEpp1qt4EHQLQJXuyb2WDQS-iNPh,
    _ids: {
        x: 1234567890123456789012345678901234567890
    }
}
>>> d3 = d1 >> d2
>>> d3.show(colored=False)
{
    x: 52,
    y: 13,
    _id: -EFuy5NAeK.LIALpBiZKK-fYQmc9AZYQQck-HiRK,
    _ids: {
        x: 1234567890123456789012345678901234567890,
        y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
    }
}
>>> (d3 >> d1.frozen).show(colored=False)
{
    x: 52,
    y: 13,
    _id: 5pwGP0LxQRbQaDEk9ztQ4V4qz.A-IIhVNTrcyt8U,
    _ids: {
        x: c.llz05T6ZXw5AlsU4xfmMxcvvHZhLl60LckZis9,
        y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
    }
}
>>> d = hdict(x=2, y=4)
>>> {"x": 2, "y": 4} == d.frozen
True
>>> {"x": 2, "y": 4} == d
True
>>> d == {"x": 2, "y": 4}
True
>>> dict(d)
{'x': 2, 'y': 4}
>>> hdict() >> {"x": 3} == {"x": 3}
True
>>> {"x": 3, "d": {"x": 7}} == hdict(x=3, d=hdict(x=7))
True
>>> hdict(x=3, d=hdict(x=7)) == {"x": 3, "d": {"x": 7}}
True
>>> {"x": 3, "_id": hdict(x=3).id} == hdict(x=3)
True
>>> hdict(x=3) == {"x": 3, "_id": hdict(x=3).id}
True
>>> hdict(x=3) == hdict(x=3)
True
>>> hdict(x=3).frozen == hdict(x=3)
True
>>> hdict(x=3) != {"x": 4}
True
>>> hdict(x=3) != hdict(x=4)
True
>>> hdict(x=3).frozen != hdict(x=4)
True
>>> hdict(x=3) != {"y": 3}
True
>>> hdict(x=3) != {"x": 3, "_id": (~hdict(x=3).hosh).id}
True
>>> hdict(x=3) != hdict(y=3)
True
>>> del d["x"]
>>> list(d)
['y']
>>> e = d >> apply(lambda y: y*7)("y")
>>> from hdict.content.aux_value import f2hosh
>>> print(f2hosh(lambda y: y*7))
54YCMDJIlsIvMQ.KJtT-vFyjg83Zgfj2xSHOgCj8
>>> print(e)
{y: "λ(4)"}
>>> e.evaluate()
>>> print(e)
{y: 28}
>>> d = d >> apply(lambda y=1: y*7, fhosh="54YCMDJIlsIvMQ.KJtT-vFyjg83Zgfj2xSHOgCj8")("y")
>>> print(d)
{y: "λ(4)"}
>>> d.evaluate()
>>> print(d)
{y: 28}
>>> hash(e.frozen) == hash(d.frozen)
True
>>> d = hdict(a=5) >> hdict(y=28)
>>> d.show(colored=False)
{
    a: 5,
    y: 28,
    _id: C-xKyWCyBL6g32KIuxoANoF9czLaJTh-emPsMqOg,
    _ids: {
        a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9
    }
}
>>> d >>= apply(lambda a: a)("x")
>>> d.show(colored=False)
{
    a: 5,
    y: 28,
    x: λ(a),
    _id: qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY,
    _ids: {
        a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
        x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp
    }
}
>>> {"_id": "qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY"} == d
True
>>> d.show(colored=False)
{
    a: 5,
    y: 28,
    x: λ(a),
    _id: qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY,
    _ids: {
        a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
        x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp
    }
}
>>> def f():
...     print("busy")
...     return 23
>>> storage = {}
>>> d >>= apply(f).o >> cache(storage, "x", "y")
>>> d.y
28
>>> d.show(colored=False)
{
    a: 5,
    y: 28,
    x: ↑↓ cached at <code>dict</code>·,
    o: λ(),
    _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
    _ids: {
        a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
        x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
        o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
    }
}
>>> d.evaluated.show(colored=False)
busy
{
    a: 5,
    y: 28,
    x: 5,
    o: 23,
    _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
    _ids: {
        a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
        x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
        o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
    }
}
>>> d.evaluated.show(colored=False)
{
    a: 5,
    y: 28,
    x: 5,
    o: 23,
    _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
    _ids: {
        a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
        y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
        x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
        o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
    }
}
Expand source code
class hdict(hdict_):
    """
    Function id is reversed before application.
    This is needed to enable handling a function as a value, under the original id.

    >>> from hdict import hdict, apply, field
    >>> from hdict.content.argument.default import default
    >>> d = hdict({"x": 3}, y=5)
    >>> d["alpha"] = 11
    >>> d.show(colored=False)
    {
        x: 3,
        y: 5,
        alpha: 11,
        _id: e6WGyTj7trk6AUUcdxGAefyG.T9j.SvBdEsHF.r5,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            alpha: A1RyW.GoA3q9-iCbCvWyWClExm1J3wI.ok6UA3Nk
        }
    }
    >>> d >>= {"beta": 12, "gamma": 17}
    >>> d["p1", "q1"] = apply(lambda x, y=3: [x**y, x/y])
    >>> d["pq"] = apply(lambda x, y=3: [x**y, x/y])
    >>> d["p2", "q2"] = apply(lambda x=2, y=None: [x**y, x/y])
    >>> f = lambda x, y: {"a": x**y, "b": x/y}
    >>> d["z1", "w1"] = apply(f)
    >>> d["z2":"a", "w2":"b"] = apply(f)
    >>> d >>= {
    ...     "r1": apply(lambda x: x**2),
    ...     "r2": apply(lambda x: x**3),
    ...     "r3": apply(lambda x: x**4),
    ...     ("ra1", "rb1"): apply(f),
    ...     (("ra2", "a"), ("rb2", "b")): apply(f),
    ... }
    >>> d["z2"]
    243
    >>> d["zz1", "ww1"] = apply(f, field("r1"), y=field("r2"))
    >>> d >>= {("zz2", "ww2"): apply(f, y=field("r2"), x=9)}  # Define external value.
    >>> d >>= {"zzzz": apply(f, y=13, x=9)}
    >>> # Non-pickable custom classes need a custom 'hosh' attribute to be applied and also to be used as a value.
    >>> from hosh import Hosh
    >>> # Example of class that could be used as a value or as a function.
    >>> from dataclasses import dataclass
    >>> @dataclass
    ... class CustomClass:
    ...     hosh = Hosh.fromid("Some.arbitrary.identifier.with.length.40")
    ...     def __call__(self, x, y):
    ...         return x + y, x / y
    >>> custom = CustomClass()
    >>> d["f"] = custom  # Custom callable handled as a value.
    >>> d["zzz1", "www1"] = apply(custom, 11, y=33)  # Custom callable being applied.
    >>> d["zzz2", "www2"] = apply(field("f"), field("r1"), y=44)  # Callable field being applied.
    >>> d.show(colored=False)
    {
        x: 3,
        y: 5,
        alpha: 11,
        beta: 12,
        gamma: 17,
        p1: λ(x y)→0,
        q1: λ(x y)→1,
        pq: λ(x y),
        p2: λ(x y)→0,
        q2: λ(x y)→1,
        z1: λ(x y)→0,
        w1: λ(x y)→1,
        z2: 243,
        w2: λ(x y)→b,
        r1: λ(x),
        r2: λ(x),
        r3: λ(x),
        ra1: λ(x y)→0,
        rb1: λ(x y)→1,
        ra2: λ(x y)→a,
        rb2: λ(x y)→b,
        zz1: λ(x=r1 y=r2)→0,
        ww1: λ(x=r1 y=r2)→1,
        zz2: λ(9 y=r2)→0,
        ww2: λ(9 y=r2)→1,
        zzzz: λ(9 13),
        f: "CustomClass()",
        zzz1: λ(11 33)→0,
        www1: λ(11 33)→1,
        zzz2: λ(r1 44)→0,
        www2: λ(r1 44)→1,
        _id: i5wtTs5qggivS-y5TNuhnM5jwokjF132M7jF.49a,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            y: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            alpha: A1RyW.GoA3q9-iCbCvWyWClExm1J3wI.ok6UA3Nk,
            beta: WM5TbiaJ1gLqKRSFiY3VkZEu1PwQcaAokBKBPrWg,
            gamma: yb-HU.jSxd496XfId1J..MkX7xfUPJOL1-07hHdt,
            p1: Qs0J0I.AhR.brQjpYwUJqDNLk-zKd7FmG0g7gdd1,
            q1: VOAVwyrrdC7eIsjnVkqdpsqUfhprKzKriATFEOQI,
            pq: KtTWRcFQRKVgTJabGMgY-HAQWJ1TZGnOYw7NU.1K,
            p2: qb0H0MqNit0rLwk6CsC4Q2bxpCmBQ581eoGI39sr,
            q2: Sjsl-.MJJ3SK2.INLAJ-0R5BwlfG.tccIpxPFRtB,
            z1: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
            w1: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
            z2: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
            w2: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
            r1: FO3NXIQIi7TBFw1FqLRJYo13EA.uu4Y-L17Fmx0z,
            r2: HorxHsNCdpkm270yeTZ-vREjjFXWIYC99ALidDVU,
            r3: bWc33lXvXHIJXix5Jw2.Nhw0EIsv3TuAa7t8Ix5q,
            ra1: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
            rb1: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
            ra2: w8obIVknqdoKk.hDUN8TE2M-KiFh-yCCXtxNdrJ4,
            rb2: T0hCevYdBG6vWZ3R5Nba.jXacMTFFUW5OjOX4yAO,
            zz1: FB6W9j12qWZ34fUwyrBETzFuAXRB-xn7O1PGhr2j,
            ww1: IhchjkRfjLXpnsC6zl-TFugIQrnUIdB7Wsgpnely,
            zz2: LE5ohPby7q4dNu3qhqgucRcCt.pd87O.CyKWloqe,
            ww2: -RBf-UiccAG3sTH0UFC6C.YFmYcpTRA.0PFP6Oun,
            zzzz: Irbj-xVP8rEIPoylOTNmiuJ-lGdx0dpzIPgq-169,
            f: Some.arbitrary.identifier.with.length.40,
            zzz1: TBw0fUZZo1WlI9uczNuF0w4vC06u6YvzJyNPVEi1,
            www1: WqqXpIpMwinaXxYNqRjj4qttDcKXN.gcGjARpOSh,
            zzz2: .mJim0y-LMUYZi01GN8MTPkHj79JtFdREf7g40ug,
            www2: jwtsaf1IZMG6sWqprXZnc.n-ilyfncwhL3Qr.-Md
        }
    }
    >>> d["p1"]
    243
    >>> from hdict import value
    >>> d.evaluate()
    >>> d = hdict(x=2)
    >>> g = lambda x, y: [x + y, x / y]
    >>> d["z"] = apply(f, 2, y=3)
    >>> d["w", "v"] = apply(f, field("x"), y=33)
    >>> d["f"] = f
    >>> d = d >> apply(field("f"), field("x"), y=default(3), nonexistent_parameter=7)("w3", "v3") # todo: : nonexistent parameter should raise an exception
    >>> d >>= apply(field("f"), field("x"), y=default(3))("w", "v")
    >>> d["w2", "v2"] = apply(field("f"), field("x"), y=default(3))
    >>> d >>= {"z": apply(f, field("x"), y=3), ("w", "v"): apply(g, y=7)}
    >>> d >>= apply(f, field("x"), y=3)("z9") * apply(g, y=7)("w9", "v9")
    >>> pp = apply(f, field("x"), y=3)("z") >> apply(g, y=7)("w", "v")
    >>> d >>= {"x": 3} >> pp >> apply(g, y=7)("w", "v")
    >>> from hdict import _
    >>> a1 = apply(f, y=_(1, 2, 4, ..., 128))
    >>> a2 = apply(f, _(0, 3, 6, ..., 9), y=_(0, 3, 6, ..., 9))
    >>> ppp = hdict() >> a2.sample()("k", "t")
    >>> ppp.show(colored=False)
    {
        k: λ(9 9)→0,
        t: λ(9 9)→1,
        _id: dK-iumb4L5nkFVT9LCkdk3daQtuC.ORk6JwWMhnt,
        _ids: {
            k: rHTgwW.w2SsbcvBlSnWWddLH4vgyXlM1Fhxqr48f,
            t: IldA8m-uSN9lJcE4TBtjTcY-sSiA33mzxQ2k-wpN
        }
    }
    >>> ppp.k
    387420489
    >>> a1("z")
    z=λ(x y=~[1 2 .*. 128])
    >>> a2(w="a", v="b")
    (('w', 'a'), ('v', 'b'))=λ(x=~[0 3 .+. 9] y=~[0 3 .+. 9])
    >>> p = a1("z") >> a2(w="a", v="b")
    >>> h = lambda a, b=4: 5
    >>> app = apply(h, a=_(0, 3, 6, ..., 9))
    >>> app
    λ(a=~[0 3 .+. 9] b=default(4))
    >>> app.c
    c=λ(a=~[0 3 .+. 9] b=default(4))
    >>> sampled = app.sample(0).c
    >>> sampled
    c=λ(9 b=default(4))
    >>> r = hdict() >> sampled
    >>> r.show(colored=False)
    {
        c: λ(9 b=4),
        _id: Bbe5mzn0oCuHZ.Y84-jaEnh3jcrgD8av6IZezKEG,
        _ids: {
            c: 6EehD7OoZe2REI.1YsVLKxSF4hJoYxfOZJLbF.Aj
        }
    }
    >>> r.evaluated.show(colored=False)
    {
        c: 5,
        _id: Bbe5mzn0oCuHZ.Y84-jaEnh3jcrgD8av6IZezKEG,
        _ids: {
            c: 6EehD7OoZe2REI.1YsVLKxSF4hJoYxfOZJLbF.Aj
        }
    }
    >>> from random import Random
    >>> rnd = Random(0)
    >>> p1 = p.sample(rnd)
    >>> d["w"]
    10
    >>> d >>= p1
    >>> d["z"] = apply(f, 2, y=3)
    >>> d["w", "v"] = apply(f, _.x, y=_.x)
    >>> d["w", "v"] = apply(_.f, _.x, y=default(3))
    >>> d = hdict() >> {"z": apply(f, 7, y=3), ("w", "v"): apply(g, default(6), y=7)}
    >>> d = hdict(w=6) >> (apply(f, _["w"], y=3)(z="z") >> apply(g, x=_(1,2,3,...,5), y=7)("ww", "v")).sample(0)
    >>> p = apply(f, y=_(1, 2, 4, ..., 128))("z") >> apply(f, y=_(0, 3, 6, ..., 9))(w="a", v="b")
    >>> d.show(colored=False)
    {
        w: 6,
        z: λ(x=w 3)→z,
        ww: λ(4 7)→0,
        v: λ(4 7)→1,
        _id: x4TxaVuAymsh97Yr.15Oc1ekllvlpECk091124RM,
        _ids: {
            w: CZ7Jm5fQMZ3fZJ3kAVOi0FYK-exFqPqgoYLsGxGl,
            z: No1nN40OXnJ.zOyAvoxwCjyD06cUDiXTZQh4q8xa,
            ww: qZepp.wpXCOYQrwnVIwoZ4kR9pIuMGDQpvRevv80,
            v: wxkjBSP54cKEfxKE1Zte-2dDll3G9Nd-yDh3CLas
        }
    }
    >>> d = hdict(x=3) >> p.sample(rnd)
    >>> d.show(colored=False)
    {
        x: 3,
        z: λ(x 16),
        w: λ(x 9)→a,
        v: λ(x 9)→b,
        _id: 22b-e.CtRGVSoMkektNzHYSVZTouhL2jAHLyPd4Q,
        _ids: {
            x: KGWjj0iyLAn1RG6RTGtsGE3omZraJM6xO.kvG5pr,
            z: 64cxw0HmJ0fydH7By6i0HrbuwA759XexTu3Bu0Zd,
            w: p1Z5umNo12DHCZtKbh2EClW6TZxv.M447HlALWhv,
            v: HbYbR1RjPdU4jixjW7xSxslRpYx9W6Oiay7maK6F
        }
    }
    >>> d1 = hdict(x=52, y=13)
    >>> d2 = hdict(x=value(52, hosh="1234567890123456789012345678901234567890"))
    >>> d1.show(colored=False)
    {
        x: 52,
        y: 13,
        _id: 5pwGP0LxQRbQaDEk9ztQ4V4qz.A-IIhVNTrcyt8U,
        _ids: {
            x: c.llz05T6ZXw5AlsU4xfmMxcvvHZhLl60LckZis9,
            y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
        }
    }
    >>> d2.show(colored=False)
    {
        x: 52,
        _id: kYzgpPdRgQSYSEpp1qt4EHQLQJXuyb2WDQS-iNPh,
        _ids: {
            x: 1234567890123456789012345678901234567890
        }
    }
    >>> d3 = d1 >> d2
    >>> d3.show(colored=False)
    {
        x: 52,
        y: 13,
        _id: -EFuy5NAeK.LIALpBiZKK-fYQmc9AZYQQck-HiRK,
        _ids: {
            x: 1234567890123456789012345678901234567890,
            y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
        }
    }
    >>> (d3 >> d1.frozen).show(colored=False)
    {
        x: 52,
        y: 13,
        _id: 5pwGP0LxQRbQaDEk9ztQ4V4qz.A-IIhVNTrcyt8U,
        _ids: {
            x: c.llz05T6ZXw5AlsU4xfmMxcvvHZhLl60LckZis9,
            y: zplslThZYha4haD2VmGxZqrFSw5RJcFJd2E-Ku6s
        }
    }

    >>> d = hdict(x=2, y=4)
    >>> {"x": 2, "y": 4} == d.frozen
    True
    >>> {"x": 2, "y": 4} == d
    True
    >>> d == {"x": 2, "y": 4}
    True
    >>> dict(d)
    {'x': 2, 'y': 4}
    >>> hdict() >> {"x": 3} == {"x": 3}
    True
    >>> {"x": 3, "d": {"x": 7}} == hdict(x=3, d=hdict(x=7))
    True
    >>> hdict(x=3, d=hdict(x=7)) == {"x": 3, "d": {"x": 7}}
    True
    >>> {"x": 3, "_id": hdict(x=3).id} == hdict(x=3)
    True
    >>> hdict(x=3) == {"x": 3, "_id": hdict(x=3).id}
    True
    >>> hdict(x=3) == hdict(x=3)
    True
    >>> hdict(x=3).frozen == hdict(x=3)
    True
    >>> hdict(x=3) != {"x": 4}
    True
    >>> hdict(x=3) != hdict(x=4)
    True
    >>> hdict(x=3).frozen != hdict(x=4)
    True
    >>> hdict(x=3) != {"y": 3}
    True
    >>> hdict(x=3) != {"x": 3, "_id": (~hdict(x=3).hosh).id}
    True
    >>> hdict(x=3) != hdict(y=3)
    True
    >>> del d["x"]
    >>> list(d)
    ['y']
    >>> e = d >> apply(lambda y: y*7)("y")
    >>> from hdict.content.aux_value import f2hosh
    >>> print(f2hosh(lambda y: y*7))
    54YCMDJIlsIvMQ.KJtT-vFyjg83Zgfj2xSHOgCj8
    >>> print(e)
    {y: "λ(4)"}
    >>> e.evaluate()
    >>> print(e)
    {y: 28}
    >>> d = d >> apply(lambda y=1: y*7, fhosh="54YCMDJIlsIvMQ.KJtT-vFyjg83Zgfj2xSHOgCj8")("y")
    >>> print(d)
    {y: "λ(4)"}
    >>> d.evaluate()
    >>> print(d)
    {y: 28}
    >>> hash(e.frozen) == hash(d.frozen)
    True
    >>> d = hdict(a=5) >> hdict(y=28)
    >>> d.show(colored=False)
    {
        a: 5,
        y: 28,
        _id: C-xKyWCyBL6g32KIuxoANoF9czLaJTh-emPsMqOg,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9
        }
    }
    >>> d >>= apply(lambda a: a)("x")
    >>> d.show(colored=False)
    {
        a: 5,
        y: 28,
        x: λ(a),
        _id: qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp
        }
    }
    >>> {"_id": "qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY"} == d
    True
    >>> d.show(colored=False)
    {
        a: 5,
        y: 28,
        x: λ(a),
        _id: qI8rmiUzMTSO1pMkCeQJpHTAOw4xuooFqM41iIiY,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp
        }
    }
    >>> def f():
    ...     print("busy")
    ...     return 23
    >>> storage = {}
    >>> d >>= apply(f).o >> cache(storage, "x", "y")
    >>> d.y
    28
    >>> d.show(colored=False)
    {
        a: 5,
        y: 28,
        x: ↑↓ cached at `dict`·,
        o: λ(),
        _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
            o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
        }
    }
    >>> d.evaluated.show(colored=False)
    busy
    {
        a: 5,
        y: 28,
        x: 5,
        o: 23,
        _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
            o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
        }
    }
    >>> d.evaluated.show(colored=False)
    {
        a: 5,
        y: 28,
        x: 5,
        o: 23,
        _id: 4FdTqXVIMKldUnZgrrp315c78KHD9yu7T.Nr5zGv,
        _ids: {
            a: ecvgo-CBPi7wRWIxNzuo1HgHQCbdvR058xi6zmr2,
            y: -2A0hTRBN1wtIKQxLzRcYDBkhv1hu-dMY-24Jye9,
            x: sxkIk6E9l8oScCyoGDlzrqJ9QgpIpl5PCBvHlERp,
            o: Re1o0YXNebYNezPrVv2dOrFxtgLQutD-b-SHFRbo
        }
    }
    """

Ancestors

Inherited members

class sample (*values: list[int | float], rnd: int | random.Random = 0, maxdigits=28)

A lazily evaluated list of values

>>> (s := sample(1, 2, 3, ..., 9).values)
[1 2 .+. 9]
>>> (s := sample(2, 4, 8, ..., 1024).values)
[2 4 .*. 1024]
>>> (s := sample(2, -4, 8, ..., 12).values)
[2 -4 8]
Expand source code
class sample(AbsMetaArgument):
    """
    A lazily evaluated list of values

    >>> (s := sample(1, 2, 3, ..., 9).values)
    [1 2 .+. 9]
    >>> (s := sample(2, 4, 8, ..., 1024).values)
    [2 4 .*. 1024]
    >>> (s := sample(2, -4, 8, ..., 12).values)
    [2 -4 8]
    """

    sampleable = True

    def __init__(self, *values: list[int | float], rnd: int | Random = 0, maxdigits=28):
        self.rnd = rnd
        # todo: : accept list of non numeric types (categoric)?
        prog = list2progression(values, maxdigits=maxdigits)
        if prog.n.is_infinite():  # pragma: no cover
            raise Exception(f"Cannot sample from an infinite list: {prog}")
        self.values = prog

    def sample(self, rnd: int | Random = None):
        if rnd is None:
            rnd = self.rnd
        if isinstance(rnd, int):
            rnd = Random(rnd)
        if not isinstance(rnd, Random):  # pragma: no cover
            raise Exception(f"Sampling needs an integer seed or a Random object.")
        idx = rnd.randint(0, self.values.n - 1)
        return value(self.values[idx])

    def __repr__(self):
        return f"~{self.values}"

Ancestors

Class variables

var sampleable

Methods

def sample(self, rnd: int | random.Random = None)
Expand source code
def sample(self, rnd: int | Random = None):
    if rnd is None:
        rnd = self.rnd
    if isinstance(rnd, int):
        rnd = Random(rnd)
    if not isinstance(rnd, Random):  # pragma: no cover
        raise Exception(f"Sampling needs an integer seed or a Random object.")
    idx = rnd.randint(0, self.values.n - 1)
    return value(self.values[idx])
class value (val: object, hosh: hosh.hosh_.Hosh | str = None, hdict=None)

Wrapper for any Python object except AbsAny instances

>>> x = 5
>>> from hdict.content.value import value
>>> v = value(x, "1234567890123456789012345678901234567890")
>>> v
5
>>> v.hosh.id
'1234567890123456789012345678901234567890'

Args

val:
hosh:
hdict
optional reference to the object if it has a hdict counterpart (e.g.: pandas DF)
Expand source code
class value(AbsBaseArgument, AbsEntry):
    """
    Wrapper for any Python object except AbsAny instances

    >>> x = 5
    >>> from hdict.content.value import value
    >>> v = value(x, "1234567890123456789012345678901234567890")
    >>> v
    5
    >>> v.hosh.id
    '1234567890123456789012345678901234567890'

    """

    isevaluated = True

    def __init__(self, val: object, hosh: Hosh | str = None, hdict=None):
        """

        Args:
            val:
            hosh:
            hdict:  optional reference to the object if it has a hdict counterpart (e.g.: pandas DF)
        """
        from hdict.abs import AbsAny

        if isinstance(val, AbsAny):  # pragma: no cover
            raise Exception(f"Cannot handle objects of type '{type(val).__name__}' as raw values for hdict.")
        self.value = self._value = val
        if isinstance(hosh, str):
            hosh = Hosh.fromid(hosh)
        self.hosh = v2hosh(self.value) if hosh is None else hosh
        self.hdict = hdict

    def __repr__(self):
        return repr(self.value)

Ancestors

Inherited members