veridret-plugins-core 1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- veridret_plugins_core-1/.gitignore +14 -0
- veridret_plugins_core-1/LICENSE.md +50 -0
- veridret_plugins_core-1/PKG-INFO +20 -0
- veridret_plugins_core-1/README.md +4 -0
- veridret_plugins_core-1/pyproject.toml +95 -0
- veridret_plugins_core-1/src/veridret_plugins/core/__init__.py +11 -0
- veridret_plugins_core-1/src/veridret_plugins/core/_plugin.py +63 -0
- veridret_plugins_core-1/src/veridret_plugins/core/call.py +64 -0
- veridret_plugins_core-1/src/veridret_plugins/core/cmptools/__init__.py +8 -0
- veridret_plugins_core-1/src/veridret_plugins/core/cmptools/reverse.py +66 -0
- veridret_plugins_core-1/src/veridret_plugins/core/cmptools/unordered.py +48 -0
- veridret_plugins_core-1/src/veridret_plugins/core/functools/__init__.py +8 -0
- veridret_plugins_core-1/src/veridret_plugins/core/functools/call.py +43 -0
- veridret_plugins_core-1/src/veridret_plugins/core/functools/call_right.py +65 -0
- veridret_plugins_core-1/src/veridret_plugins/core/functools/compose_left.py +66 -0
- veridret_plugins_core-1/src/veridret_plugins/core/functools/compose_right.py +66 -0
- veridret_plugins_core-1/src/veridret_plugins/core/functools/identity.py +38 -0
- veridret_plugins_core-1/src/veridret_plugins/core/iterator.py +49 -0
- veridret_plugins_core-1/src/veridret_plugins/core/itertools/__init__.py +8 -0
- veridret_plugins_core-1/src/veridret_plugins/core/itertools/filter.py +50 -0
- veridret_plugins_core-1/src/veridret_plugins/core/itertools/fold_left.py +60 -0
- veridret_plugins_core-1/src/veridret_plugins/core/itertools/map.py +49 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: BSD-3-Clause -->
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 Jonathan Gruber.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms,
|
|
6
|
+
with or without modification,
|
|
7
|
+
are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
10
|
+
this list of conditions
|
|
11
|
+
and the following disclaimer.
|
|
12
|
+
|
|
13
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
14
|
+
this list of conditions
|
|
15
|
+
and the following disclaimer
|
|
16
|
+
in the documentation and/or other materials
|
|
17
|
+
provided with the distribution.
|
|
18
|
+
|
|
19
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
20
|
+
may be used to endorse or promote products derived from this software
|
|
21
|
+
without specific prior written permission.
|
|
22
|
+
|
|
23
|
+
THIS SOFTWARE IS PROVIDED
|
|
24
|
+
BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
25
|
+
“AS IS”
|
|
26
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
27
|
+
INCLUDING,
|
|
28
|
+
BUT NOT LIMITED TO,
|
|
29
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
30
|
+
AND FITNESS FOR A PARTICULAR PURPOSE
|
|
31
|
+
ARE DISCLAIMED.
|
|
32
|
+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
33
|
+
FOR ANY DIRECT,
|
|
34
|
+
INDIRECT,
|
|
35
|
+
INCIDENTAL,
|
|
36
|
+
SPECIAL,
|
|
37
|
+
EXEMPLARY,
|
|
38
|
+
OR CONSEQUENTIAL DAMAGES
|
|
39
|
+
(INCLUDING,
|
|
40
|
+
BUT NOT LIMITED TO,
|
|
41
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
42
|
+
LOSS OF USE, DATA, OR PROFITS;
|
|
43
|
+
OR BUSINESS INTERRUPTION)
|
|
44
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
45
|
+
WHETHER IN CONTRACT,
|
|
46
|
+
STRICT LIABILITY,
|
|
47
|
+
OR TORT
|
|
48
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
49
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
50
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: veridret-plugins-core
|
|
3
|
+
Version: 1
|
|
4
|
+
Import-Name: veridret_plugins.core
|
|
5
|
+
Import-Namespace: veridret_plugins
|
|
6
|
+
Summary: The *official* Python package of the *official* standard core VerIdRet plugins
|
|
7
|
+
Project-URL: homepage, https://codeberg.org/jonathan-gruber-jg/veridret-plugins-core.git
|
|
8
|
+
Project-URL: source, https://codeberg.org/jonathan-gruber-jg/veridret-plugins-core.git
|
|
9
|
+
Author-email: Jonathan Gruber <jonathan.gruber.jg@gmail.com>
|
|
10
|
+
License-Expression: BSD-3-Clause
|
|
11
|
+
License-File: LICENSE.md
|
|
12
|
+
Requires-Python: ~=3.14.6
|
|
13
|
+
Requires-Dist: pydantic~=2.13
|
|
14
|
+
Requires-Dist: veridret~=1.0
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
<!-- SPDX-License-Identifier: BSD-3-Clause -->
|
|
18
|
+
|
|
19
|
+
`veridret-plugins-core` is the *official* Python package
|
|
20
|
+
of the *official* standard core VerIdRet plugins.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
[build-system]
|
|
4
|
+
requires = [
|
|
5
|
+
'hatchling',
|
|
6
|
+
]
|
|
7
|
+
build-backend = 'hatchling.build'
|
|
8
|
+
|
|
9
|
+
[project]
|
|
10
|
+
name = 'veridret-plugins-core'
|
|
11
|
+
dynamic = [
|
|
12
|
+
'version',
|
|
13
|
+
]
|
|
14
|
+
description = """\
|
|
15
|
+
The *official* Python package \
|
|
16
|
+
of the *official* standard core VerIdRet plugins\
|
|
17
|
+
"""
|
|
18
|
+
readme = 'README.md'
|
|
19
|
+
license = 'BSD-3-Clause'
|
|
20
|
+
license-files = [
|
|
21
|
+
'LICENSE.md',
|
|
22
|
+
]
|
|
23
|
+
import-names = [
|
|
24
|
+
'veridret_plugins.core',
|
|
25
|
+
]
|
|
26
|
+
import-namespaces = [
|
|
27
|
+
'veridret_plugins',
|
|
28
|
+
]
|
|
29
|
+
requires-python = '~= 3.14.6'
|
|
30
|
+
dependencies = [
|
|
31
|
+
'pydantic ~= 2.13',
|
|
32
|
+
'veridret ~= 1.0',
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[[project.authors]]
|
|
36
|
+
name = 'Jonathan Gruber'
|
|
37
|
+
email = 'jonathan.gruber.jg@gmail.com'
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
homepage = 'https://codeberg.org/jonathan-gruber-jg/veridret-plugins-core.git'
|
|
41
|
+
source = 'https://codeberg.org/jonathan-gruber-jg/veridret-plugins-core.git'
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = [
|
|
45
|
+
'src/veridret_plugins',
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[tool.hatch.version]
|
|
49
|
+
path = 'src/veridret_plugins/core/__init__.py'
|
|
50
|
+
|
|
51
|
+
[tool.pylint.main]
|
|
52
|
+
disable = [
|
|
53
|
+
'missing-class-docstring',
|
|
54
|
+
'missing-function-docstring',
|
|
55
|
+
'too-few-public-methods',
|
|
56
|
+
'too-many-instance-attributes',
|
|
57
|
+
'unspecified-encoding',
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.pylint.format]
|
|
61
|
+
max-line-length = 79
|
|
62
|
+
|
|
63
|
+
[tool.pylint.variables]
|
|
64
|
+
init-import = false
|
|
65
|
+
|
|
66
|
+
[tool.mypy]
|
|
67
|
+
mypy_path = [
|
|
68
|
+
'${MYPY_CONFIG_FILE_DIR}/src',
|
|
69
|
+
]
|
|
70
|
+
packages = [
|
|
71
|
+
'veridret_plugins',
|
|
72
|
+
]
|
|
73
|
+
strict = true
|
|
74
|
+
strict_equality_for_none = true
|
|
75
|
+
warn_return_any = false
|
|
76
|
+
|
|
77
|
+
[tool.pyrefly]
|
|
78
|
+
project-includes = [
|
|
79
|
+
'src',
|
|
80
|
+
]
|
|
81
|
+
min-severity = 'warn'
|
|
82
|
+
preset = 'strict'
|
|
83
|
+
enabled-ignores = [
|
|
84
|
+
'pyrefly',
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[tool.pyrefly.errors]
|
|
88
|
+
implicit-any-lambda = 'ignore'
|
|
89
|
+
|
|
90
|
+
[tool.pyright]
|
|
91
|
+
include = [
|
|
92
|
+
'src',
|
|
93
|
+
]
|
|
94
|
+
#typeCheckingMode = 'strict'
|
|
95
|
+
enableTypeIgnoreComments = false
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Plugin utilities.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Annotated, Any, ClassVar
|
|
8
|
+
|
|
9
|
+
import pydantic
|
|
10
|
+
|
|
11
|
+
import veridret.plugin
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'AnnotatedCall',
|
|
15
|
+
'Call',
|
|
16
|
+
'evaluate_call',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
class Call(pydantic.BaseModel):
|
|
20
|
+
"""
|
|
21
|
+
A plugin call.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
model_config: ClassVar = pydantic.ConfigDict(frozen=True)
|
|
25
|
+
|
|
26
|
+
plugin: str
|
|
27
|
+
args: dict[str, object] = pydantic.Field(
|
|
28
|
+
default_factory=dict,
|
|
29
|
+
validation_alias=pydantic.AliasChoices('arguments', 'args'),
|
|
30
|
+
serialization_alias='arguments',
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
def evaluate_call(call: Call) -> Any:
|
|
34
|
+
"""
|
|
35
|
+
Evaluate a plugin call.
|
|
36
|
+
|
|
37
|
+
:param call: The plugin call,
|
|
38
|
+
:return: The result of the plugin call.
|
|
39
|
+
:raise Exception:
|
|
40
|
+
If the plugin cannot be loaded
|
|
41
|
+
or the call to it fails.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
return veridret.plugin.load(call.plugin)(call.args)
|
|
45
|
+
|
|
46
|
+
def _inst_anno_call(value: Call | str) -> Call:
|
|
47
|
+
match value:
|
|
48
|
+
case Call():
|
|
49
|
+
return value
|
|
50
|
+
case str():
|
|
51
|
+
return Call(plugin=value)
|
|
52
|
+
|
|
53
|
+
type AnnotatedCall = Annotated[
|
|
54
|
+
Call,
|
|
55
|
+
pydantic.ValidateAs(
|
|
56
|
+
Call | str, # pyright: ignore[reportArgumentType]
|
|
57
|
+
_inst_anno_call,
|
|
58
|
+
),
|
|
59
|
+
]
|
|
60
|
+
"""
|
|
61
|
+
:class:`Call` but annotated for Pydantic to instantiate the type
|
|
62
|
+
from a string ``x`` via ``Call(plugin=x)``.
|
|
63
|
+
"""
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Evaluate a call expression.
|
|
5
|
+
|
|
6
|
+
In particular,
|
|
7
|
+
the plugin evaluates ``id a[1] a[2] ... a[n]``,
|
|
8
|
+
where ``id`` is the identity function
|
|
9
|
+
and each operand ``a[i]`` is the result of a plugin call.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
import functools
|
|
14
|
+
from typing import Any, cast, overload
|
|
15
|
+
|
|
16
|
+
import pydantic
|
|
17
|
+
|
|
18
|
+
from veridret_plugins.core import _plugin
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
'call',
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
class _Args(pydantic.BaseModel):
|
|
25
|
+
operands: tuple[_plugin.AnnotatedCall, ...] = pydantic.Field(
|
|
26
|
+
(),
|
|
27
|
+
validation_alias=pydantic.AliasChoices('operands', 'items'),
|
|
28
|
+
serialization_alias='operands',
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
@overload
|
|
32
|
+
def _try_call[T, U](func: Callable[[T], U], arg: T) -> U:
|
|
33
|
+
...
|
|
34
|
+
@overload
|
|
35
|
+
def _try_call(func: object, arg: object) -> Any:
|
|
36
|
+
...
|
|
37
|
+
def _try_call(func: object, arg: object) -> Any:
|
|
38
|
+
return cast(Callable[[Any], Any], func)(arg)
|
|
39
|
+
|
|
40
|
+
def _identity[T](obj: T, /) -> T:
|
|
41
|
+
return obj
|
|
42
|
+
|
|
43
|
+
def call(args: dict[str, object]) -> Any:
|
|
44
|
+
"""
|
|
45
|
+
Call the plugin.
|
|
46
|
+
|
|
47
|
+
:param args: A dictionary of the plugin's arguments.
|
|
48
|
+
:return: The result of the call expression specified by ``args``.
|
|
49
|
+
:raise Exception:
|
|
50
|
+
If ``args`` is invalid,
|
|
51
|
+
evaluating any of the plugin calls
|
|
52
|
+
that evaluate to the operands of the call expression
|
|
53
|
+
fails,
|
|
54
|
+
or any of the individual calls
|
|
55
|
+
made in evaluating the whole call expression
|
|
56
|
+
fails.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
validated_args = _Args.model_validate(args, strict=True, by_name=False)
|
|
60
|
+
return functools.reduce(
|
|
61
|
+
_try_call,
|
|
62
|
+
map(_plugin.evaluate_call, validated_args.operands),
|
|
63
|
+
initial=_identity,
|
|
64
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Reflect/reverse rich comparisons upon an object.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
import dataclasses
|
|
9
|
+
import operator
|
|
10
|
+
import types
|
|
11
|
+
from typing import Any, final, Never, override
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'call',
|
|
15
|
+
'Reverse',
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
@final
|
|
19
|
+
@dataclasses.dataclass(frozen=True)
|
|
20
|
+
class Reverse[T]:
|
|
21
|
+
"""
|
|
22
|
+
A comparison key that reflects/reverses rich comparisons.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
value: T
|
|
26
|
+
|
|
27
|
+
def _cmp_impl(
|
|
28
|
+
self, other: object, op: Callable[[Any, Any], object],
|
|
29
|
+
) -> Any | types.NotImplementedType:
|
|
30
|
+
if not isinstance(other, Reverse):
|
|
31
|
+
return NotImplemented
|
|
32
|
+
return op(other.value, self.value)
|
|
33
|
+
|
|
34
|
+
def __lt__(self, other: object) -> Any | types.NotImplementedType:
|
|
35
|
+
return self._cmp_impl(other, operator.lt)
|
|
36
|
+
|
|
37
|
+
def __gt__(self, other: object) -> Any | types.NotImplementedType:
|
|
38
|
+
return self._cmp_impl(other, operator.gt)
|
|
39
|
+
|
|
40
|
+
def __le__(self, other: object) -> Any | types.NotImplementedType:
|
|
41
|
+
return self._cmp_impl(other, operator.le)
|
|
42
|
+
|
|
43
|
+
def __ge__(self, other: object) -> Any | types.NotImplementedType:
|
|
44
|
+
return self._cmp_impl(other, operator.ge)
|
|
45
|
+
|
|
46
|
+
@override
|
|
47
|
+
@classmethod
|
|
48
|
+
def __init_subclass__(cls) -> Never:
|
|
49
|
+
raise TypeError(
|
|
50
|
+
f'type {Reverse.__qualname__!r} is not an acceptable base type',
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def call(args: dict[str, object]) -> type[Reverse[Any]]:
|
|
54
|
+
"""
|
|
55
|
+
Call the plugin.
|
|
56
|
+
|
|
57
|
+
:param args:
|
|
58
|
+
A dictionary of the plugin's arguments;
|
|
59
|
+
unused.
|
|
60
|
+
:return: :class:`Reverse`.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Unused.
|
|
64
|
+
del args
|
|
65
|
+
|
|
66
|
+
return Reverse
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Disable ordering comparisons
|
|
5
|
+
(``<``, ``<=``, ``>``, and ``>=``)
|
|
6
|
+
upon an object.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import dataclasses
|
|
10
|
+
from typing import Any, final, Never, override
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'call',
|
|
14
|
+
'Unordered',
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
@final
|
|
18
|
+
@dataclasses.dataclass(frozen=True)
|
|
19
|
+
class Unordered[T]:
|
|
20
|
+
"""
|
|
21
|
+
A comparison key that disables comparisons
|
|
22
|
+
with ``<``, ``<=``, ``>``, or ``>=``
|
|
23
|
+
while preserving those with ``==`` or ``!=``.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
value: T
|
|
27
|
+
|
|
28
|
+
@override
|
|
29
|
+
@classmethod
|
|
30
|
+
def __init_subclass__(cls) -> Never:
|
|
31
|
+
raise TypeError(
|
|
32
|
+
f'type {Unordered.__qualname__!r} is not an acceptable base type',
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def call(args: dict[str, object]) -> type[Unordered[Any]]:
|
|
36
|
+
"""
|
|
37
|
+
Call the plugin.
|
|
38
|
+
|
|
39
|
+
:param args:
|
|
40
|
+
A dictionary of the plugin's arguments;
|
|
41
|
+
unused.
|
|
42
|
+
:return: :class:`Unordered`.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
# Unused.
|
|
46
|
+
del args
|
|
47
|
+
|
|
48
|
+
return Unordered
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
The function call operator.
|
|
5
|
+
|
|
6
|
+
The operator is in fact the identity function over the functions;
|
|
7
|
+
letting ``op`` denote the operator,
|
|
8
|
+
we have ``op f x = (op f) x = f x``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from typing import Any, Protocol
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
'Call',
|
|
16
|
+
'call',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
class Call(Protocol):
|
|
20
|
+
"""
|
|
21
|
+
A protocol for the function call operator.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __call__[F: Callable[[Any], Any]](self, obj: F, /) -> F:
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
def _identity[F: Callable[[Any], Any]](func: F, /) -> F:
|
|
28
|
+
return func
|
|
29
|
+
|
|
30
|
+
def call(args: dict[str, object]) -> Call:
|
|
31
|
+
"""
|
|
32
|
+
Call the plugin.
|
|
33
|
+
|
|
34
|
+
:param args:
|
|
35
|
+
A dictionary of the plugin's arguments;
|
|
36
|
+
unused.
|
|
37
|
+
:return: The function call operator.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# Unused.
|
|
41
|
+
del args
|
|
42
|
+
|
|
43
|
+
return _identity
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
The reverse or rightist function call operator.
|
|
5
|
+
|
|
6
|
+
The operator is in fact the normal function call operator
|
|
7
|
+
with the first two arguments switched;
|
|
8
|
+
letting ``op`` denote the operator,
|
|
9
|
+
we have ``op x f = f x``.
|
|
10
|
+
Since,
|
|
11
|
+
in an expression like ``operator a b``,
|
|
12
|
+
the normal function call operator calls
|
|
13
|
+
the *left* operand ``a`` upon the right operand ``b``
|
|
14
|
+
while the reverse function call operator calls
|
|
15
|
+
the *right* operand ``b`` upon the left operand ``a``,
|
|
16
|
+
we refer to the latter operator as also
|
|
17
|
+
the *right*\\ ist function call operator.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from collections.abc import Callable
|
|
21
|
+
from typing import Protocol
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
'call',
|
|
25
|
+
'CallRight',
|
|
26
|
+
'CallRightOne'
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
class CallRightOne[T](Protocol):
|
|
30
|
+
"""
|
|
31
|
+
A protocol for the reverse function call operator
|
|
32
|
+
with the first argument bound to an object of type ``T``.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __call__[U](self, func: Callable[[T], U], /) -> U:
|
|
36
|
+
...
|
|
37
|
+
|
|
38
|
+
class CallRight(Protocol):
|
|
39
|
+
"""
|
|
40
|
+
A protocol for the reverse function call operator.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __call__[T](self, obj: T, /) -> CallRightOne[T]:
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
def _call_right[T](obj: T, /) -> CallRightOne[T]:
|
|
47
|
+
def call_right_one[U](func: Callable[[T], U], /) -> U:
|
|
48
|
+
return func(obj)
|
|
49
|
+
|
|
50
|
+
return call_right_one
|
|
51
|
+
|
|
52
|
+
def call(args: dict[str, object]) -> CallRight:
|
|
53
|
+
"""
|
|
54
|
+
Call the plugin.
|
|
55
|
+
|
|
56
|
+
:param args:
|
|
57
|
+
A dictionary of the plugin's arguments;
|
|
58
|
+
unused.
|
|
59
|
+
:return: A curried reverse unary-function-call operator.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
# Unused.
|
|
63
|
+
del args
|
|
64
|
+
|
|
65
|
+
return _call_right
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
The leftist function composition operator.
|
|
5
|
+
|
|
6
|
+
The order of the composed functions is opposite
|
|
7
|
+
that of the usual function composition operator in mathematics;
|
|
8
|
+
letting ``op`` denote the operator,
|
|
9
|
+
we have ``op f g x = (op f g) x = g (f x)``.
|
|
10
|
+
Since the function ``g`` with which ``f`` is composed
|
|
11
|
+
thus ends up on the *left* of ``f``
|
|
12
|
+
in the preceding evaluation of ``op f g x``,
|
|
13
|
+
we call the operator the *left*\\ ist function composition operator.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from collections.abc import Callable
|
|
17
|
+
from typing import Protocol
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
'call',
|
|
21
|
+
'ComposeLeft',
|
|
22
|
+
'ComposeLeftOne',
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
class ComposeLeftOne[T, U](Protocol):
|
|
26
|
+
"""
|
|
27
|
+
A protocol for the leftist function composition operator
|
|
28
|
+
with the first argument bound to a function of type ``T -> U``.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __call__[V](self, func: Callable[[U], V], /) -> Callable[[T], V]:
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
class ComposeLeft(Protocol):
|
|
35
|
+
"""
|
|
36
|
+
A protocol for the leftist function composition operator.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __call__[T, U](
|
|
40
|
+
self, func: Callable[[T], U], /,
|
|
41
|
+
) -> ComposeLeftOne[T, U]:
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
def _compose_left[T, U](func1: Callable[[T], U], /) -> ComposeLeftOne[T, U]:
|
|
45
|
+
def compose_left_one[V](func2: Callable[[U], V], /) -> Callable[[T], V]:
|
|
46
|
+
def compose_left_two(obj: T, /) -> V:
|
|
47
|
+
return func2(func1(obj))
|
|
48
|
+
|
|
49
|
+
return compose_left_two
|
|
50
|
+
|
|
51
|
+
return compose_left_one
|
|
52
|
+
|
|
53
|
+
def call(args: dict[str, object]) -> ComposeLeft:
|
|
54
|
+
"""
|
|
55
|
+
Call the plugin.
|
|
56
|
+
|
|
57
|
+
:param args:
|
|
58
|
+
A dictionary of the plugin's arguments;
|
|
59
|
+
unused.
|
|
60
|
+
:return: The leftist function composition operator.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Unused.
|
|
64
|
+
del args
|
|
65
|
+
|
|
66
|
+
return _compose_left
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
The rightist function composition operator.
|
|
5
|
+
|
|
6
|
+
The operator corresponds to the usual function composition operator
|
|
7
|
+
in mathematics;
|
|
8
|
+
letting ``op`` denote the operator,
|
|
9
|
+
we have ``op f g x = (op f g) x = f (g x)``.
|
|
10
|
+
Since the function ``g`` with which ``f`` is composed
|
|
11
|
+
thus ends up on the *right* of ``f``
|
|
12
|
+
in the preceding evaluation of ``op f g x``,
|
|
13
|
+
we call the operator the *right*\\ ist function composition operator.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from collections.abc import Callable
|
|
17
|
+
from typing import Protocol
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
'call',
|
|
21
|
+
'ComposeRight',
|
|
22
|
+
'ComposeRightOne',
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
class ComposeRightOne[T, U](Protocol):
|
|
26
|
+
"""
|
|
27
|
+
A protocol for the rightist function composition operator
|
|
28
|
+
with the first argument bound to a function of type ``T -> U``.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __call__[V](self, func: Callable[[V], T], /) -> Callable[[V], U]:
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
class ComposeRight(Protocol):
|
|
35
|
+
"""
|
|
36
|
+
A protocol for the rightist function composition operator.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __call__[T, U](
|
|
40
|
+
self, func: Callable[[T], U], /,
|
|
41
|
+
) -> ComposeRightOne[T, U]:
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
def _compose_right[T, U](func1: Callable[[T], U], /) -> ComposeRightOne[T, U]:
|
|
45
|
+
def compose_right_one[V](func2: Callable[[V], T], /) -> Callable[[V], U]:
|
|
46
|
+
def compose_right_two(obj: V, /) -> U:
|
|
47
|
+
return func1(func2(obj))
|
|
48
|
+
|
|
49
|
+
return compose_right_two
|
|
50
|
+
|
|
51
|
+
return compose_right_one
|
|
52
|
+
|
|
53
|
+
def call(args: dict[str, object]) -> ComposeRight:
|
|
54
|
+
"""
|
|
55
|
+
Call the plugin.
|
|
56
|
+
|
|
57
|
+
:param args:
|
|
58
|
+
A dictionary of the plugin's arguments;
|
|
59
|
+
unused.
|
|
60
|
+
:return: The rightist function composition operator.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
# Unused.
|
|
64
|
+
del args
|
|
65
|
+
|
|
66
|
+
return _compose_right
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
The identity function.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Protocol
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
'call',
|
|
11
|
+
'Identity',
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
class Identity(Protocol):
|
|
15
|
+
"""
|
|
16
|
+
A protocol for the identity function.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __call__[T](self, obj: T, /) -> T:
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
def _identity[T](obj: T, /) -> T:
|
|
23
|
+
return obj
|
|
24
|
+
|
|
25
|
+
def call(args: dict[str, object]) -> Identity:
|
|
26
|
+
"""
|
|
27
|
+
Call the plugin.
|
|
28
|
+
|
|
29
|
+
:param args:
|
|
30
|
+
A dictionary of the plugin's arguments;
|
|
31
|
+
unused.
|
|
32
|
+
:return: The identity function.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# Unused.
|
|
36
|
+
del args
|
|
37
|
+
|
|
38
|
+
return _identity
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Construct an iterator over a fixed sequence.
|
|
5
|
+
|
|
6
|
+
In particular,
|
|
7
|
+
the plugin constructs an iterator
|
|
8
|
+
over the sequence ``(a[0], a[1], ..., a[n])``,
|
|
9
|
+
where each ``a[i]`` is the result of a plugin call
|
|
10
|
+
and is computed only once the iterator is made to yield it.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from collections.abc import Iterator
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
import pydantic
|
|
17
|
+
|
|
18
|
+
from veridret_plugins.core import _plugin
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
'call',
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
class _Args(pydantic.BaseModel):
|
|
25
|
+
operands: tuple[_plugin.AnnotatedCall, ...] = pydantic.Field(
|
|
26
|
+
(),
|
|
27
|
+
validation_alias=pydantic.AliasChoices('operands', 'items'),
|
|
28
|
+
serialization_alias='operands',
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def call(args: dict[str, object]) -> Iterator[Any]:
|
|
32
|
+
"""
|
|
33
|
+
Call the plugin.
|
|
34
|
+
|
|
35
|
+
:param args: A dictionary of the plugin's arguments.
|
|
36
|
+
:return: An iterator of the sequence specified by ``args``.
|
|
37
|
+
:raise Exception:
|
|
38
|
+
If ``args`` is invalid.
|
|
39
|
+
|
|
40
|
+
Since the plugin calls that evaluate to the items yielded by the iterator
|
|
41
|
+
are each only evaluated once the iterator is made to yield them,
|
|
42
|
+
if evaluating any of those plugin calls fails,
|
|
43
|
+
then attempting to yield the item
|
|
44
|
+
to which the plugin call would have evaluated
|
|
45
|
+
raises an exception.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
validated_args = _Args.model_validate(args, strict=True, by_name=False)
|
|
49
|
+
return map(_plugin.evaluate_call, validated_args.operands)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
The ``filter`` higher-order function over the iterables.
|
|
5
|
+
|
|
6
|
+
Letting ``filter_`` denote the function,
|
|
7
|
+
``filter_ p it`` is equivalent to the Python ``filter(p, it)``,
|
|
8
|
+
including the special case where ``p`` is ``None``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
12
|
+
from typing import Protocol
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
'call',
|
|
16
|
+
'Filter',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
class Filter(Protocol):
|
|
20
|
+
"""
|
|
21
|
+
A protocol for the ``filter`` higher-order function over the iterables.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __call__[T](
|
|
25
|
+
self, pred: Callable[[T], object] | None, /,
|
|
26
|
+
) -> Callable[[Iterable[T]], Iterator[T]]:
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
def _filter[T](
|
|
30
|
+
pred: Callable[[T], object] | None, /,
|
|
31
|
+
) -> Callable[[Iterable[T]], Iterator[T]]:
|
|
32
|
+
def filter_one(iterable: Iterable[T], /) -> Iterator[T]:
|
|
33
|
+
return filter(pred, iterable)
|
|
34
|
+
|
|
35
|
+
return filter_one
|
|
36
|
+
|
|
37
|
+
def call(args: dict[str, object]) -> Filter:
|
|
38
|
+
"""
|
|
39
|
+
Call the plugin.
|
|
40
|
+
|
|
41
|
+
:param args:
|
|
42
|
+
A dictionary of the plugin's arguments;
|
|
43
|
+
unused.
|
|
44
|
+
:return: The ``filter`` higher-order function over the iterables.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
# Unused.
|
|
48
|
+
del args
|
|
49
|
+
|
|
50
|
+
return _filter
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
The left-associative variant of the ``fold`` higher-order over the iterables.
|
|
5
|
+
|
|
6
|
+
Letting ``fold_left`` denote the function,
|
|
7
|
+
``fold_left f z it`` is equivalent to the Python
|
|
8
|
+
``functools.reduce(lambda x, y: f(x)(y), it, initial=z)``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from collections.abc import Callable, Iterable
|
|
12
|
+
import functools
|
|
13
|
+
from typing import Protocol
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
'call',
|
|
17
|
+
'FoldLeft',
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
class FoldLeft(Protocol):
|
|
21
|
+
"""
|
|
22
|
+
A protocol for the left-associative variant of the ``fold`` higher-order
|
|
23
|
+
over the iterables.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __call__[T, U](
|
|
27
|
+
self, func: Callable[[T], Callable[[U], T]], /,
|
|
28
|
+
) -> Callable[[T], Callable[[Iterable[U]], T]]:
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
def _fold_left[T, U](
|
|
32
|
+
func: Callable[[T], Callable[[U], T]], /,
|
|
33
|
+
) -> Callable[[T], Callable[[Iterable[U]], T]]:
|
|
34
|
+
def uncurried_func(x: T, y: U) -> T:
|
|
35
|
+
return func(x)(y)
|
|
36
|
+
|
|
37
|
+
def fold_left_one(seed: T, /) -> Callable[[Iterable[U]], T]:
|
|
38
|
+
def fold_left_two(iterable: Iterable[U], /) -> T:
|
|
39
|
+
return functools.reduce(uncurried_func, iterable, initial=seed)
|
|
40
|
+
|
|
41
|
+
return fold_left_two
|
|
42
|
+
|
|
43
|
+
return fold_left_one
|
|
44
|
+
|
|
45
|
+
def call(args: dict[str, object]) -> FoldLeft:
|
|
46
|
+
"""
|
|
47
|
+
Call the plugin.
|
|
48
|
+
|
|
49
|
+
:param args:
|
|
50
|
+
A dictionary of the plugin's arguments;
|
|
51
|
+
unused.
|
|
52
|
+
:return:
|
|
53
|
+
The left-associative variant of the ``fold`` higher-order
|
|
54
|
+
over the iterables.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
# Unused.
|
|
58
|
+
del args
|
|
59
|
+
|
|
60
|
+
return _fold_left
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
The ``map`` higher-order function over the iterables.
|
|
5
|
+
|
|
6
|
+
Letting ``map_`` denote the function,
|
|
7
|
+
``map_ f it`` is equivalent to the Python ``map(f, it)``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
11
|
+
from typing import Protocol
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'call',
|
|
15
|
+
'Map',
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
class Map(Protocol):
|
|
19
|
+
"""
|
|
20
|
+
A protocol for the ``map`` higher-order function over the iterables.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __call__[T, U](
|
|
24
|
+
self, func: Callable[[T], U], /
|
|
25
|
+
) -> Callable[[Iterable[T]], Iterator[U]]:
|
|
26
|
+
...
|
|
27
|
+
|
|
28
|
+
def _map[T, U](
|
|
29
|
+
func: Callable[[T], U], /,
|
|
30
|
+
) -> Callable[[Iterable[T]], Iterator[U]]:
|
|
31
|
+
def map_one(iterable: Iterable[T], /) -> Iterator[U]:
|
|
32
|
+
return map(func, iterable)
|
|
33
|
+
|
|
34
|
+
return map_one
|
|
35
|
+
|
|
36
|
+
def call(args: dict[str, object]) -> Map:
|
|
37
|
+
"""
|
|
38
|
+
Call the plugin.
|
|
39
|
+
|
|
40
|
+
:param args:
|
|
41
|
+
A dictionary of the plugin's arguments;
|
|
42
|
+
unused.
|
|
43
|
+
:return: A ``map`` higher-order function over the iterables.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Unused.
|
|
47
|
+
del args
|
|
48
|
+
|
|
49
|
+
return _map
|