Module hdict.content.argument.apply
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 __future__ import annotations
from inspect import isfunction, isbuiltin, isclass
from inspect import signature
from itertools import chain
from random import Random
from hosh import Hosh
from hdict.content.argument import AbsBaseArgument, AbsArgument
from hdict.content.argument.field import field
from hdict.text.customjson import truncate
from hdict.content.aux_value import f2hosh
def getattr_(__o: object, name: str, __default=None):
"""
>>> from hdict import _, apply
>>> (_ >> {"o": "str"} >> apply(getattr, _.o, "find").r).evaluated.show(colored=False) # doctest:+ELLIPSIS
{
o: "str",
r: "<built-in method find of str object at 0x...>",
_id: zU3QsJ.a9fjr8eeoqwaPKlufC6.AEacZZBWScM39,
_ids: {
o: PdHGvI1xk.ZG7wt3-2TQm-GjFXidwYNw8xsD3Wpe,
r: BKrY9O9ExQh8k0xjgINKKV2-JD6qEEjDOIVR1yyq
}
}
"""
return getattr(__o, name, __default)
# todo hide unneeded attrs to avoid poluting namespace for output field
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
Functions
def getattr_(__o: object, name: str)
-
>>> from hdict import _, apply >>> (_ >> {"o": "str"} >> apply(getattr, _.o, "find").r).evaluated.show(colored=False) # doctest:+ELLIPSIS { o: "str", r: "<built-in method find of str object at 0x...>", _id: zU3QsJ.a9fjr8eeoqwaPKlufC6.AEacZZBWScM39, _ids: { o: PdHGvI1xk.ZG7wt3-2TQm-GjFXidwYNw8xsD3Wpe, r: BKrY9O9ExQh8k0xjgINKKV2-JD6qEEjDOIVR1yyq } }
Expand source code
def getattr_(__o: object, name: str, __default=None): """ >>> from hdict import _, apply >>> (_ >> {"o": "str"} >> apply(getattr, _.o, "find").r).evaluated.show(colored=False) # doctest:+ELLIPSIS { o: "str", r: "<built-in method find of str object at 0x...>", _id: zU3QsJ.a9fjr8eeoqwaPKlufC6.AEacZZBWScM39, _ids: { o: PdHGvI1xk.ZG7wt3-2TQm-GjFXidwYNw8xsD3Wpe, r: BKrY9O9ExQh8k0xjgINKKV2-JD6qEEjDOIVR1yyq } } """ return getattr(__o, name, __default)
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