tensnap 0.1.0__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.
- tensnap-0.1.0/MANIFEST.in +4 -0
- tensnap-0.1.0/PKG-INFO +75 -0
- tensnap-0.1.0/README.md +41 -0
- tensnap-0.1.0/pyproject.toml +65 -0
- tensnap-0.1.0/setup.cfg +4 -0
- tensnap-0.1.0/tensnap/__init__.py +13 -0
- tensnap-0.1.0/tensnap/bindings/__init__.py +0 -0
- tensnap-0.1.0/tensnap/bindings/basic/__init__.py +56 -0
- tensnap-0.1.0/tensnap/bindings/basic/accessor.py +260 -0
- tensnap-0.1.0/tensnap/bindings/basic/action.py +59 -0
- tensnap-0.1.0/tensnap/bindings/basic/chart.py +204 -0
- tensnap-0.1.0/tensnap/bindings/basic/parameter.py +520 -0
- tensnap-0.1.0/tensnap/bindings/mesa/__init__.py +20 -0
- tensnap-0.1.0/tensnap/bindings/mesa/accessor.py +98 -0
- tensnap-0.1.0/tensnap/bindings/mesa/datacollector.py +204 -0
- tensnap-0.1.0/tensnap/bindings/mesa/handler.py +163 -0
- tensnap-0.1.0/tensnap/examples/cgol.py +58 -0
- tensnap-0.1.0/tensnap/examples/cgol_viz.py +35 -0
- tensnap-0.1.0/tensnap/examples/flock.py +190 -0
- tensnap-0.1.0/tensnap/examples/flock_viz.py +60 -0
- tensnap-0.1.0/tensnap/examples/hk.py +191 -0
- tensnap-0.1.0/tensnap/examples/hk_viz.py +95 -0
- tensnap-0.1.0/tensnap/examples/mushroom.py +125 -0
- tensnap-0.1.0/tensnap/examples/sirs.py +370 -0
- tensnap-0.1.0/tensnap/examples/sirs_viz_graph.py +48 -0
- tensnap-0.1.0/tensnap/examples/sirs_viz_grid.py +50 -0
- tensnap-0.1.0/tensnap/examples/sugarscape.py +190 -0
- tensnap-0.1.0/tensnap/examples/sugarscape_viz.py +70 -0
- tensnap-0.1.0/tensnap/models/__init__.py +36 -0
- tensnap-0.1.0/tensnap/models/agent.py +191 -0
- tensnap-0.1.0/tensnap/models/environment.py +530 -0
- tensnap-0.1.0/tensnap/models/types.py +78 -0
- tensnap-0.1.0/tensnap/scenario.py +317 -0
- tensnap-0.1.0/tensnap/server.py +544 -0
- tensnap-0.1.0/tensnap/sim_loop.py +229 -0
- tensnap-0.1.0/tensnap/utils/__init__.py +2 -0
- tensnap-0.1.0/tensnap/utils/attr.py +204 -0
- tensnap-0.1.0/tensnap/utils/func.py +21 -0
- tensnap-0.1.0/tensnap/utils/model.py +30 -0
- tensnap-0.1.0/tensnap/utils/object.py +357 -0
- tensnap-0.1.0/tensnap/utils/ws.py +130 -0
- tensnap-0.1.0/tensnap.egg-info/PKG-INFO +75 -0
- tensnap-0.1.0/tensnap.egg-info/SOURCES.txt +50 -0
- tensnap-0.1.0/tensnap.egg-info/dependency_links.txt +1 -0
- tensnap-0.1.0/tensnap.egg-info/requires.txt +13 -0
- tensnap-0.1.0/tensnap.egg-info/top_level.txt +1 -0
- tensnap-0.1.0/tests/test_basic.py +15 -0
- tensnap-0.1.0/tests/test_environment.py +398 -0
- tensnap-0.1.0/tests/test_parameters.py +334 -0
- tensnap-0.1.0/tests/test_scenario.py +394 -0
- tensnap-0.1.0/tests/test_server.py +329 -0
- tensnap-0.1.0/tests/test_sim_loop.py +252 -0
tensnap-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tensnap
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Agent-based model visualization toolkit - Python bindings
|
|
5
|
+
Author-email: billstark001 <billstark001@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/billstark001/tensnap
|
|
8
|
+
Project-URL: Documentation, https://github.com/billstark001/tensnap/tree/main/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/billstark001/tensnap
|
|
10
|
+
Project-URL: Issues, https://github.com/billstark001/tensnap/issues
|
|
11
|
+
Keywords: agent-based-modeling,simulation,visualization,abm
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: numpy>=1.24.0
|
|
23
|
+
Requires-Dist: networkx>=3.0
|
|
24
|
+
Requires-Dist: msgpack>=1.0.5
|
|
25
|
+
Requires-Dist: websockets>=12.0
|
|
26
|
+
Requires-Dist: typing-extensions>=4.9.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=1.7.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
34
|
+
|
|
35
|
+
# Tensnap Python Bindings
|
|
36
|
+
|
|
37
|
+
Python bindings for Tensnap - an agent-based model visualization toolkit.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install tensnap
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from tensnap import Scenario
|
|
49
|
+
import asyncio
|
|
50
|
+
|
|
51
|
+
# Create a scenario
|
|
52
|
+
scenario = Scenario(name="my-simulation", port=8765)
|
|
53
|
+
|
|
54
|
+
# Define your model logic
|
|
55
|
+
# See examples/ directory for complete examples
|
|
56
|
+
|
|
57
|
+
# Run the server
|
|
58
|
+
asyncio.run(scenario.run())
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Examples
|
|
62
|
+
|
|
63
|
+
Check the `examples/` directory for complete simulations:
|
|
64
|
+
|
|
65
|
+
- `flock.py` - Flocking behavior
|
|
66
|
+
- `sirs.py` - SIRS epidemic model
|
|
67
|
+
- `sugarscape.py` - Sugarscape economic model
|
|
68
|
+
|
|
69
|
+
## Documentation
|
|
70
|
+
|
|
71
|
+
Full documentation: <https://github.com/billstark001/tensnap>
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
See LICENSE file in the repository root.
|
tensnap-0.1.0/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Tensnap Python Bindings
|
|
2
|
+
|
|
3
|
+
Python bindings for Tensnap - an agent-based model visualization toolkit.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install tensnap
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from tensnap import Scenario
|
|
15
|
+
import asyncio
|
|
16
|
+
|
|
17
|
+
# Create a scenario
|
|
18
|
+
scenario = Scenario(name="my-simulation", port=8765)
|
|
19
|
+
|
|
20
|
+
# Define your model logic
|
|
21
|
+
# See examples/ directory for complete examples
|
|
22
|
+
|
|
23
|
+
# Run the server
|
|
24
|
+
asyncio.run(scenario.run())
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
Check the `examples/` directory for complete simulations:
|
|
30
|
+
|
|
31
|
+
- `flock.py` - Flocking behavior
|
|
32
|
+
- `sirs.py` - SIRS epidemic model
|
|
33
|
+
- `sugarscape.py` - Sugarscape economic model
|
|
34
|
+
|
|
35
|
+
## Documentation
|
|
36
|
+
|
|
37
|
+
Full documentation: <https://github.com/billstark001/tensnap>
|
|
38
|
+
|
|
39
|
+
## License
|
|
40
|
+
|
|
41
|
+
See LICENSE file in the repository root.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tensnap"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Agent-based model visualization toolkit - Python bindings"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "billstark001", email = "billstark001@example.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["agent-based-modeling", "simulation", "visualization", "abm"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Visualization",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"numpy>=1.24.0",
|
|
28
|
+
"networkx>=3.0",
|
|
29
|
+
"msgpack>=1.0.5",
|
|
30
|
+
"websockets>=12.0",
|
|
31
|
+
"typing-extensions>=4.9.0"
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/billstark001/tensnap"
|
|
36
|
+
Documentation = "https://github.com/billstark001/tensnap/tree/main/docs"
|
|
37
|
+
Repository = "https://github.com/billstark001/tensnap"
|
|
38
|
+
Issues = "https://github.com/billstark001/tensnap/issues"
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
dev = [
|
|
42
|
+
"pytest>=7.4.0",
|
|
43
|
+
"pytest-asyncio>=0.21.0",
|
|
44
|
+
"pytest-cov>=4.1.0",
|
|
45
|
+
"mypy>=1.7.0",
|
|
46
|
+
"ruff>=0.1.0",
|
|
47
|
+
"black>=23.0.0"
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[tool.mypy]
|
|
51
|
+
python_version = "3.10"
|
|
52
|
+
strict = true
|
|
53
|
+
warn_return_any = true
|
|
54
|
+
warn_unused_configs = true
|
|
55
|
+
disallow_untyped_defs = true
|
|
56
|
+
|
|
57
|
+
[tool.ruff]
|
|
58
|
+
line-length = 88
|
|
59
|
+
target-version = "py310"
|
|
60
|
+
select = ["E", "F", "B", "I", "N", "UP", "PL", "RUF"]
|
|
61
|
+
|
|
62
|
+
[tool.pytest.ini_options]
|
|
63
|
+
testpaths = ["tests"]
|
|
64
|
+
python_files = ["test_*.py", "*_test.py"]
|
|
65
|
+
addopts = "--cov=tensnap --cov-report=html --cov-report=term-missing"
|
tensnap-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# tensnap/__init__.py
|
|
2
|
+
"""TenSnap - Agent-based model visualization toolkit"""
|
|
3
|
+
|
|
4
|
+
from .server import TenSnapServer
|
|
5
|
+
from .sim_loop import SimulationLoop
|
|
6
|
+
from .scenario import SimulationScenario
|
|
7
|
+
from .models import *
|
|
8
|
+
from .bindings.basic import *
|
|
9
|
+
from .bindings.mesa import *
|
|
10
|
+
import tensnap.utils as utils
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# tensnap/bindings/basic/__init__.py
|
|
2
|
+
"""Basic bindings for TenSnap - parameter, chart, and button decorators"""
|
|
3
|
+
|
|
4
|
+
from .parameter import (
|
|
5
|
+
ParameterType,
|
|
6
|
+
ParameterTypeWithoutAction,
|
|
7
|
+
ParameterBase,
|
|
8
|
+
NumberParameter,
|
|
9
|
+
BooleanParameter,
|
|
10
|
+
StringParameter,
|
|
11
|
+
EnumParameter,
|
|
12
|
+
ActionParameter,
|
|
13
|
+
Parameter,
|
|
14
|
+
BindParametersConfig,
|
|
15
|
+
bind,
|
|
16
|
+
bind_parameters,
|
|
17
|
+
get_parameter_metadata_from_namespace,
|
|
18
|
+
get_parameter_metadata_from_object,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
from .chart import (
|
|
22
|
+
chart,
|
|
23
|
+
ChartMetadata,
|
|
24
|
+
ChartGroupMetadata,
|
|
25
|
+
ChartMetadataDict,
|
|
26
|
+
ChartGroupMetadataDict,
|
|
27
|
+
ChartProperty,
|
|
28
|
+
SimplifiedChartMetadata,
|
|
29
|
+
get_chart_metadata_from_namespace,
|
|
30
|
+
categorize_charts,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from .action import (
|
|
34
|
+
action,
|
|
35
|
+
get_action_metadata_from_namespace,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
from .accessor import (
|
|
40
|
+
|
|
41
|
+
BindUniformAgentConfig,
|
|
42
|
+
BindGridAgentConfig,
|
|
43
|
+
BindGraphAgentNXConfig,
|
|
44
|
+
BindGraphAgentConfig,
|
|
45
|
+
bind_uniform_agent,
|
|
46
|
+
bind_grid_agent,
|
|
47
|
+
bind_graph_agent_nx,
|
|
48
|
+
bind_graph_agent,
|
|
49
|
+
|
|
50
|
+
BindUniformEnvironmentConfig,
|
|
51
|
+
BindGridEnvironmentConfig,
|
|
52
|
+
BindGraphEnvironmentConfig,
|
|
53
|
+
bind_uniform_environment,
|
|
54
|
+
bind_grid_environment,
|
|
55
|
+
bind_graph_environment,
|
|
56
|
+
)
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
|
|
3
|
+
from typing import Any, cast, Callable
|
|
4
|
+
|
|
5
|
+
from tensnap.models.agent import (
|
|
6
|
+
UniformAgentAccessorDict,
|
|
7
|
+
GridAgentAccessorDict,
|
|
8
|
+
GraphAgentAccessorNXDict,
|
|
9
|
+
GraphAgentAccessorDict,
|
|
10
|
+
make_uniform_agent_accessor,
|
|
11
|
+
make_grid_agent_accessor,
|
|
12
|
+
make_graph_agent_accessor_nx,
|
|
13
|
+
make_graph_agent_accessor,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from tensnap.models.environment import (
|
|
17
|
+
GridEnvironmentAccessorDict,
|
|
18
|
+
GraphEnvironmentAccessorDict,
|
|
19
|
+
GraphEdgeAccessorNXDict,
|
|
20
|
+
GraphEdgeDict,
|
|
21
|
+
make_uniform_environment_accessor,
|
|
22
|
+
make_grid_environment_accessor,
|
|
23
|
+
make_graph_environment_accessor,
|
|
24
|
+
make_graph_edge_accessor_nx,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# region Agent Accessor Bindings
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class BindUniformAgentConfig:
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
id: str = "id",
|
|
35
|
+
color: str | bool | None = None,
|
|
36
|
+
icon: str | bool | None = None,
|
|
37
|
+
size: str | bool | None = None,
|
|
38
|
+
data: str | bool | None = None,
|
|
39
|
+
) -> None:
|
|
40
|
+
self.accessor_dict: UniformAgentAccessorDict = {
|
|
41
|
+
"id": id,
|
|
42
|
+
"color": color,
|
|
43
|
+
"icon": icon,
|
|
44
|
+
"size": size,
|
|
45
|
+
"data": data,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def __call__(self, cls):
|
|
49
|
+
cls._tensnap_bind_accessor_config_uniform = self
|
|
50
|
+
return cls
|
|
51
|
+
|
|
52
|
+
def get_accessor(self) -> Any:
|
|
53
|
+
return make_uniform_agent_accessor(**self.accessor_dict)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
bind_uniform_agent = BindUniformAgentConfig
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class BindGridAgentConfig:
|
|
60
|
+
|
|
61
|
+
def __init__(
|
|
62
|
+
self,
|
|
63
|
+
id: str = "id",
|
|
64
|
+
x: str = "x",
|
|
65
|
+
y: str = "y",
|
|
66
|
+
heading: str | bool | None = None,
|
|
67
|
+
color: str | bool | None = None,
|
|
68
|
+
icon: str | bool | None = None,
|
|
69
|
+
size: str | bool | None = None,
|
|
70
|
+
data: str | bool | None = None,
|
|
71
|
+
trajectory_length: str | bool | None = None,
|
|
72
|
+
trajectory_color: str | bool | None = None,
|
|
73
|
+
) -> None:
|
|
74
|
+
self.accessor_dict: GridAgentAccessorDict = {
|
|
75
|
+
"id": id,
|
|
76
|
+
"x": x,
|
|
77
|
+
"y": y,
|
|
78
|
+
"heading": heading,
|
|
79
|
+
"color": color,
|
|
80
|
+
"icon": icon,
|
|
81
|
+
"size": size,
|
|
82
|
+
"data": data,
|
|
83
|
+
"trajectory_length": trajectory_length,
|
|
84
|
+
"trajectory_color": trajectory_color,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
def __call__(self, cls):
|
|
88
|
+
cls._tensnap_bind_accessor_config_grid = self
|
|
89
|
+
return cls
|
|
90
|
+
|
|
91
|
+
def get_accessor(self) -> Any:
|
|
92
|
+
return make_grid_agent_accessor(**self.accessor_dict)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
bind_grid_agent = BindGridAgentConfig
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class BindGraphAgentNXConfig:
|
|
99
|
+
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
x: str | bool | None = None,
|
|
103
|
+
y: str | bool | None = None,
|
|
104
|
+
color: str | bool | None = None,
|
|
105
|
+
icon: str | bool | None = None,
|
|
106
|
+
size: str | bool | None = None,
|
|
107
|
+
data: str | bool | None = None,
|
|
108
|
+
) -> None:
|
|
109
|
+
self.accessor_dict: GraphAgentAccessorNXDict = {
|
|
110
|
+
"x": x,
|
|
111
|
+
"y": y,
|
|
112
|
+
"color": color,
|
|
113
|
+
"icon": icon,
|
|
114
|
+
"size": size,
|
|
115
|
+
"data": data,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
def __call__(self, cls):
|
|
119
|
+
cls._tensnap_bind_accessor_config_graph_nx = self
|
|
120
|
+
return cls
|
|
121
|
+
|
|
122
|
+
def get_accessor(self) -> Any:
|
|
123
|
+
return make_graph_agent_accessor_nx(**self.accessor_dict)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
bind_graph_agent_nx = BindGraphAgentNXConfig
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class BindGraphAgentConfig:
|
|
130
|
+
|
|
131
|
+
def __init__(
|
|
132
|
+
self,
|
|
133
|
+
id: str = "id",
|
|
134
|
+
x: str | bool | None = None,
|
|
135
|
+
y: str | bool | None = None,
|
|
136
|
+
color: str | bool | None = None,
|
|
137
|
+
icon: str | bool | None = None,
|
|
138
|
+
size: str | bool | None = None,
|
|
139
|
+
data: str | bool | None = None,
|
|
140
|
+
) -> None:
|
|
141
|
+
self.accessor_dict: GraphAgentAccessorDict = {
|
|
142
|
+
"id": id,
|
|
143
|
+
"x": x,
|
|
144
|
+
"y": y,
|
|
145
|
+
"color": color,
|
|
146
|
+
"icon": icon,
|
|
147
|
+
"size": size,
|
|
148
|
+
"data": data,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
def __call__(self, cls):
|
|
152
|
+
cls._tensnap_bind_accessor_config_graph = self
|
|
153
|
+
return cls
|
|
154
|
+
|
|
155
|
+
def get_accessor(self) -> Any:
|
|
156
|
+
return make_graph_agent_accessor(**self.accessor_dict)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
bind_graph_agent = BindGraphAgentConfig
|
|
160
|
+
|
|
161
|
+
# endregion
|
|
162
|
+
|
|
163
|
+
# region Environment Accessor Bindings
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class BindUniformEnvironmentConfig:
|
|
167
|
+
|
|
168
|
+
def __init__(
|
|
169
|
+
self,
|
|
170
|
+
) -> None:
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
def __call__(self, cls):
|
|
174
|
+
cls._tensnap_bind_accessor_config_uniform = self
|
|
175
|
+
return cls
|
|
176
|
+
|
|
177
|
+
def get_accessor(self, id: str) -> Any:
|
|
178
|
+
return make_uniform_environment_accessor(id=id)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
bind_uniform_environment = BindUniformEnvironmentConfig
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class BindGridEnvironmentConfig:
|
|
185
|
+
|
|
186
|
+
def __init__(
|
|
187
|
+
self,
|
|
188
|
+
width: str = "width",
|
|
189
|
+
height: str = "height",
|
|
190
|
+
coord_offset: str | bool | None = None,
|
|
191
|
+
background: str | bool | None = None,
|
|
192
|
+
trajectory_length: str | bool | None = None,
|
|
193
|
+
trajectory_color: str | bool | None = None,
|
|
194
|
+
) -> None:
|
|
195
|
+
self.accessor_dict: GridEnvironmentAccessorDict = {
|
|
196
|
+
"id": "id",
|
|
197
|
+
"width": width,
|
|
198
|
+
"height": height,
|
|
199
|
+
"coord_offset": coord_offset,
|
|
200
|
+
"background": background,
|
|
201
|
+
"trajectory_length": trajectory_length,
|
|
202
|
+
"trajectory_color": trajectory_color,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
def __call__(self, cls):
|
|
206
|
+
cls._tensnap_bind_accessor_config_grid = self
|
|
207
|
+
return cls
|
|
208
|
+
|
|
209
|
+
def get_accessor(self, id: str) -> Any:
|
|
210
|
+
self.accessor_dict["id"] = id
|
|
211
|
+
return make_grid_environment_accessor(**self.accessor_dict)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
bind_grid_environment = BindGridEnvironmentConfig
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class BindGraphEnvironmentConfig:
|
|
218
|
+
|
|
219
|
+
def __init__(
|
|
220
|
+
self,
|
|
221
|
+
edges: str = "edges",
|
|
222
|
+
directed: bool = False,
|
|
223
|
+
style: str | bool | None = None,
|
|
224
|
+
width: str | bool | None = None,
|
|
225
|
+
color: str | bool | None = None,
|
|
226
|
+
edge_accessor: Callable[[Any], "GraphEdgeDict"] | bool = True,
|
|
227
|
+
) -> None:
|
|
228
|
+
self.accessor_dict: GraphEnvironmentAccessorDict = {
|
|
229
|
+
"id": "id",
|
|
230
|
+
"edges": edges,
|
|
231
|
+
}
|
|
232
|
+
self.edge_accessor_dict: GraphEdgeAccessorNXDict = {
|
|
233
|
+
"directed": directed,
|
|
234
|
+
"style": style,
|
|
235
|
+
"width": width,
|
|
236
|
+
"color": color,
|
|
237
|
+
}
|
|
238
|
+
self.edge_accessor = edge_accessor
|
|
239
|
+
|
|
240
|
+
def __call__(self, cls):
|
|
241
|
+
cls._tensnap_bind_accessor_config_graph = self
|
|
242
|
+
return cls
|
|
243
|
+
|
|
244
|
+
def get_accessor(self, id: str) -> Any:
|
|
245
|
+
self.accessor_dict["id"] = id
|
|
246
|
+
return make_graph_environment_accessor(**self.accessor_dict)
|
|
247
|
+
|
|
248
|
+
def get_edge_accessor(self) -> Any:
|
|
249
|
+
if self.edge_accessor is True:
|
|
250
|
+
# Create a default edge accessor
|
|
251
|
+
return make_graph_edge_accessor_nx(**self.edge_accessor_dict)
|
|
252
|
+
elif self.edge_accessor is False:
|
|
253
|
+
# No edge accessor, return identity function
|
|
254
|
+
return lambda x: x
|
|
255
|
+
else:
|
|
256
|
+
# Use the provided edge accessor
|
|
257
|
+
return self.edge_accessor
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
bind_graph_environment = BindGraphEnvironmentConfig
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# tensnap/bindings/basic/buttons.py
|
|
2
|
+
"""Button decorators and bindings"""
|
|
3
|
+
|
|
4
|
+
from typing import Any, Callable, TypeVar, Dict, List, Tuple
|
|
5
|
+
|
|
6
|
+
from asyncio import iscoroutinefunction
|
|
7
|
+
from inspect import ismethod
|
|
8
|
+
from functools import wraps
|
|
9
|
+
|
|
10
|
+
from .parameter import ActionParameter
|
|
11
|
+
|
|
12
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def action(
|
|
16
|
+
id: str | None = None, label: str | None = None, allow_runtime_change: bool = True
|
|
17
|
+
) -> Callable[[F], F]:
|
|
18
|
+
"""Decorator to define a button"""
|
|
19
|
+
orig_id = id
|
|
20
|
+
|
|
21
|
+
def decorator(func_orig: F) -> F:
|
|
22
|
+
if ismethod(func_orig):
|
|
23
|
+
if iscoroutinefunction(func_orig):
|
|
24
|
+
|
|
25
|
+
@wraps(func_orig)
|
|
26
|
+
async def func(*args, **kwargs) -> Any: # type: ignore
|
|
27
|
+
return await func_orig(*args, **kwargs)
|
|
28
|
+
|
|
29
|
+
else:
|
|
30
|
+
|
|
31
|
+
@wraps(func_orig)
|
|
32
|
+
def func(*args, **kwargs) -> Any: # type: ignore
|
|
33
|
+
return func_orig(*args, **kwargs)
|
|
34
|
+
|
|
35
|
+
else:
|
|
36
|
+
func = func_orig # type: ignore
|
|
37
|
+
id = orig_id or func.__name__
|
|
38
|
+
param = ActionParameter(
|
|
39
|
+
id=id, label=label or "", allow_runtime_change=allow_runtime_change
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Store parameter and action info on the function
|
|
43
|
+
func._tensnap_action = param # type: ignore
|
|
44
|
+
return func # type: ignore
|
|
45
|
+
|
|
46
|
+
return decorator
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_action_metadata_from_namespace(namespace: Dict[str, Any]):
|
|
50
|
+
"""Find all action-decorated functions in a given namespace"""
|
|
51
|
+
actions: List[Tuple[str, Callable, ActionParameter]] = []
|
|
52
|
+
for name, attr in namespace.items():
|
|
53
|
+
if name.startswith('__') and name.endswith('__'):
|
|
54
|
+
continue
|
|
55
|
+
if callable(attr) and hasattr(attr, "_tensnap_action"):
|
|
56
|
+
param = getattr(attr, "_tensnap_action")
|
|
57
|
+
if isinstance(param, ActionParameter):
|
|
58
|
+
actions.append((name, attr, param))
|
|
59
|
+
return actions
|