-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhandles.py
More file actions
79 lines (68 loc) · 2.88 KB
/
Copy pathhandles.py
File metadata and controls
79 lines (68 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
"""File-backed calculation handles with source-derived signatures."""
from __future__ import annotations
import inspect
import sys
from pathlib import Path
from .authoring import CalculationResults
from .definitions import Definition, Definitions
from .source import Capture, SourceError
class CalculationHandle:
def __init__(self, path: Path, function: str, fingerprint: str | None):
self.path = path
self.function = function
self.fingerprint = fingerprint
def _definition(self) -> Definition:
capture = Capture(self.path)
definition = Definitions(capture).get(self.path, self.function)
if self.fingerprint is not None and definition.fingerprint != self.fingerprint:
raise SourceError(
"STALE_BINDINGS",
"Run cso bindings to refresh the changed public interface",
)
return definition
@property
def __signature__(self) -> inspect.Signature:
definition = self._definition()
return inspect.Signature(
[
inspect.Parameter(
name,
inspect.Parameter.KEYWORD_ONLY,
default=spec.default_value
if spec.default is not None
else inspect.Parameter.empty,
annotation=int if spec.documented.numeric_type == "int" else float,
)
for name, spec in definition.parameters.items()
],
return_annotation=CalculationResults,
)
def __call__(self, **inputs: float) -> CalculationResults:
from .execution import ACTIVE, Execution, invoke
frame = sys._getframe(1)
if ACTIVE.get() is not None or frame.f_code.co_filename.endswith(".cso.py"):
return invoke(
str(self.path), function=self.function, inputs=inputs, frame=frame
)
engine = Execution(self.path, self.function, inputs)
definition = engine.planner.definitions.get(self.path, self.function)
if self.fingerprint is not None and definition.fingerprint != self.fingerprint:
raise SourceError(
"STALE_BINDINGS",
"Run cso bindings to refresh the changed public interface",
)
return engine.run(engine.root, inputs)
def load_calculation(
path: str, *, function: str, fingerprint: str | None = None
) -> CalculationHandle:
"""Bind a local calculation; loading does not execute its authored function."""
if (
Path(path).is_absolute()
or not path.endswith(".cso.py")
or not function.isidentifier()
):
raise SourceError(
"INVALID_CALL", "Use a relative .cso.py path and named function"
)
caller = Path(sys._getframe(1).f_code.co_filename).resolve()
return CalculationHandle((caller.parent / path).resolve(), function, fingerprint)