ga-graph 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.
- ga_graph-0.1.0/CHANGELOG.md +11 -0
- ga_graph-0.1.0/LICENSE +21 -0
- ga_graph-0.1.0/MANIFEST.in +2 -0
- ga_graph-0.1.0/PKG-INFO +200 -0
- ga_graph-0.1.0/README.md +164 -0
- ga_graph-0.1.0/docs/api.md +67 -0
- ga_graph-0.1.0/docs/index.md +8 -0
- ga_graph-0.1.0/pyproject.toml +86 -0
- ga_graph-0.1.0/setup.cfg +4 -0
- ga_graph-0.1.0/src/ga_graph.egg-info/PKG-INFO +200 -0
- ga_graph-0.1.0/src/ga_graph.egg-info/SOURCES.txt +35 -0
- ga_graph-0.1.0/src/ga_graph.egg-info/dependency_links.txt +1 -0
- ga_graph-0.1.0/src/ga_graph.egg-info/requires.txt +13 -0
- ga_graph-0.1.0/src/ga_graph.egg-info/top_level.txt +1 -0
- ga_graph-0.1.0/src/graph/__init__.py +39 -0
- ga_graph-0.1.0/src/graph/_version.py +3 -0
- ga_graph-0.1.0/src/graph/algorithms/TD_LBSP.py +302 -0
- ga_graph-0.1.0/src/graph/algorithms/__init__.py +3 -0
- ga_graph-0.1.0/src/graph/graphs/__init__.py +28 -0
- ga_graph-0.1.0/src/graph/graphs/action_policy.py +27 -0
- ga_graph-0.1.0/src/graph/graphs/exceptions.py +35 -0
- ga_graph-0.1.0/src/graph/graphs/graph.py +446 -0
- ga_graph-0.1.0/src/graph/graphs/link.py +52 -0
- ga_graph-0.1.0/src/graph/graphs/node.py +40 -0
- ga_graph-0.1.0/src/graph/graphs/turn.py +194 -0
- ga_graph-0.1.0/src/graph/paths/__init__.py +13 -0
- ga_graph-0.1.0/src/graph/paths/k_path_container.py +83 -0
- ga_graph-0.1.0/src/graph/paths/k_path_list.py +178 -0
- ga_graph-0.1.0/src/graph/paths/path.py +83 -0
- ga_graph-0.1.0/src/graph/paths/path_container.py +109 -0
- ga_graph-0.1.0/src/graph/paths/path_list.py +126 -0
- ga_graph-0.1.0/src/graph/py.typed +1 -0
- ga_graph-0.1.0/tests/test_graph.py +96 -0
- ga_graph-0.1.0/tests/test_paths.py +47 -0
- ga_graph-0.1.0/tests/test_time_dependent_shortest_path.py +73 -0
- ga_graph-0.1.0/tests/test_turns.py +30 -0
- ga_graph-0.1.0/tests/test_version.py +28 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-09-01
|
|
6
|
+
|
|
7
|
+
- Prepared the package for GitHub and PyPI publication as `ga-graph`.
|
|
8
|
+
- Added README, documentation, changelog, MIT license, gitignore, manifest, and typed package marker.
|
|
9
|
+
- Corrected packaging metadata, project URLs, coverage source, and GitHub Actions imports.
|
|
10
|
+
- Added a focused `pytest` suite for graph operations, path containers, turn helpers, routing, and version exports.
|
|
11
|
+
- Fixed graph neighbor filtering, cascade removals, redundant cleanup, filtered removals, k-path lookup, and time-dependent routing turn handling.
|
ga_graph-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 GA Graph contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ga_graph-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ga-graph
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight graph, turn, path, and time-dependent routing utilities.
|
|
5
|
+
Author: GA Graph contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://github.com/andreagemma/graph#readme
|
|
8
|
+
Project-URL: Issues, https://github.com/andreagemma/graph/issues
|
|
9
|
+
Project-URL: Source, https://github.com/andreagemma/graph
|
|
10
|
+
Keywords: ga-graph,graph,routing,shortest-path,transport-network
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: dill>=0.3.8
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
27
|
+
Requires-Dist: pytest-cov>=5.0; extra == "test"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
30
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
34
|
+
Requires-Dist: twine>=5.1; extra == "dev"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# GA Graph
|
|
38
|
+
|
|
39
|
+
[](https://github.com/andreagemma/graph/actions/workflows/ci.yml)
|
|
40
|
+
[](https://pypi.org/project/ga-graph/)
|
|
41
|
+
[](https://pypi.org/project/ga-graph/)
|
|
42
|
+
|
|
43
|
+
GA Graph provides lightweight dictionary-backed graph containers, path
|
|
44
|
+
collections, turn classification helpers, and a link-based time-dependent
|
|
45
|
+
shortest-path router.
|
|
46
|
+
|
|
47
|
+
The PyPI distribution is named `ga-graph`; the import package is named `graph`.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
python -m pip install ga-graph
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Development and test tools are available as extras:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python -m pip install -e ".[test]"
|
|
59
|
+
python -m pip install -e ".[dev]"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from graph import Graph
|
|
66
|
+
|
|
67
|
+
network = Graph(total_time=60, delta_t=15)
|
|
68
|
+
network.add_node("A")
|
|
69
|
+
network.add_node("B")
|
|
70
|
+
network.add_link("ab", "A", "B", cost=5)
|
|
71
|
+
|
|
72
|
+
assert network.get_link("ab").i == "A"
|
|
73
|
+
assert network.get_node_degree("A", include_in_links=False) == 1
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Graphs
|
|
77
|
+
|
|
78
|
+
`Graph` stores nodes, directed links, and turns in dictionary-backed containers.
|
|
79
|
+
Each entity keeps a required identifier plus arbitrary extra attributes.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from graph import ActionPolicy, Graph
|
|
83
|
+
|
|
84
|
+
network = Graph()
|
|
85
|
+
network.add_link(
|
|
86
|
+
"ab",
|
|
87
|
+
"A",
|
|
88
|
+
"B",
|
|
89
|
+
on_missing_node=ActionPolicy.REPLACE,
|
|
90
|
+
capacity=1200,
|
|
91
|
+
)
|
|
92
|
+
network.add_turn("ab_bc", "ab", "bc", on_missing_link=ActionPolicy.IGNORE)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Duplicate and missing references can be handled with `ActionPolicy.RAISE`,
|
|
96
|
+
`WARN`, `IGNORE`, `REPLACE`, or `SKIP`, depending on the method.
|
|
97
|
+
|
|
98
|
+
## Paths
|
|
99
|
+
|
|
100
|
+
`Path` stores a source, target, departure time, optional mode, link sequence, and
|
|
101
|
+
cumulative costs. `PathList` stores one path per `(source, target, t_start,
|
|
102
|
+
mode)` key. `KPathList` stores multiple ranked paths for the same key.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from graph import KPathList, Path
|
|
106
|
+
|
|
107
|
+
paths = KPathList()
|
|
108
|
+
paths.add_path(Path("A", "C", 0, links=["ab", "bc"], costs=[5, 9], mode="car"))
|
|
109
|
+
paths.add_path(Path("A", "C", 0, links=["ac"], costs=[12], mode="car"))
|
|
110
|
+
|
|
111
|
+
best = paths.path("A", "C", 0, "car", k=0)
|
|
112
|
+
second = paths.path("A", "C", 0, "car", k=1)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Time-Dependent Routing
|
|
116
|
+
|
|
117
|
+
`TimeDependentLinkBasedShortestPath` builds a dense routing view from a `Graph`.
|
|
118
|
+
Scalar costs are expanded across the graph time horizon; sequence costs are used
|
|
119
|
+
as piecewise-constant time profiles.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from graph import Graph, TimeDependentLinkBasedShortestPath
|
|
123
|
+
|
|
124
|
+
network = Graph(total_time=60, delta_t=15)
|
|
125
|
+
for node in ["A", "B", "C"]:
|
|
126
|
+
network.add_node(node, cost=0)
|
|
127
|
+
|
|
128
|
+
network.add_link("ab", "A", "B", cost=1)
|
|
129
|
+
network.add_link("bc", "B", "C", cost=1)
|
|
130
|
+
network.add_link("ac", "A", "C", cost=10)
|
|
131
|
+
|
|
132
|
+
router = TimeDependentLinkBasedShortestPath.from_graph(network, link_cost_field="cost")
|
|
133
|
+
path = router.shortest_paths("A", "C").path("A", "C", 0, None)
|
|
134
|
+
|
|
135
|
+
assert path.get_links() == ("ab", "bc")
|
|
136
|
+
assert path["tot_cost"] == 2
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The router supports optional mode fields, node costs, turn costs, and prohibited
|
|
140
|
+
turn fields.
|
|
141
|
+
|
|
142
|
+
## API Summary
|
|
143
|
+
|
|
144
|
+
- `Graph(t0=0, total_time=60, delta_t=15, **kwargs)`
|
|
145
|
+
- `Graph.add_node(idx, on_existing=ActionPolicy.RAISE, **kwargs)`
|
|
146
|
+
- `Graph.add_link(idx, i, j, on_existing=..., on_missing_node=..., **kwargs)`
|
|
147
|
+
- `Graph.add_turn(idx, in_link, out_link, on_existing=..., on_missing_link=..., **kwargs)`
|
|
148
|
+
- `Graph.get_node(idx)`, `Graph.get_link(idx)`, `Graph.get_turn(idx)`
|
|
149
|
+
- `Graph.remove_node(idx, cascade=False)`, `Graph.remove_link(idx, cascade=False)`
|
|
150
|
+
- `Graph.remove_redundants()`
|
|
151
|
+
- `Path(source, target, t_start, links=None, costs=None, mode=None, ...)`
|
|
152
|
+
- `PathList()`
|
|
153
|
+
- `KPathList()`
|
|
154
|
+
- `TurnType.parse(value)` and `TurnType.classify_turn(...)`
|
|
155
|
+
- `TimeDependentLinkBasedShortestPath.from_graph(graph, ...)`
|
|
156
|
+
- `TimeDependentLinkBasedShortestPath.shortest_paths(source, targets=None, t_start=0)`
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
GA Graph supports Python 3.10 and newer.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
python -m pip install -e ".[dev]"
|
|
164
|
+
python -m compileall -q src
|
|
165
|
+
python -m pytest --cov=graph --cov-report=term-missing
|
|
166
|
+
ruff format --check .
|
|
167
|
+
ruff check .
|
|
168
|
+
mypy
|
|
169
|
+
python -m pip check
|
|
170
|
+
python -m build
|
|
171
|
+
python -m twine check dist/*
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## GitHub Repository Setup
|
|
175
|
+
|
|
176
|
+
This project is prepared for the future repository `andreagemma/graph`.
|
|
177
|
+
|
|
178
|
+
1. Create the empty repository on GitHub.
|
|
179
|
+
2. Initialize the local repository if needed and push the project to `main`.
|
|
180
|
+
3. Confirm the CI workflow passes on GitHub.
|
|
181
|
+
4. Configure the PyPI Trusted Publisher for project `ga-graph`, owner
|
|
182
|
+
`andreagemma`, repository `graph`, workflow `release.yml`, and environment
|
|
183
|
+
`pypi`.
|
|
184
|
+
|
|
185
|
+
## Releases
|
|
186
|
+
|
|
187
|
+
`src/graph/_version.py` is the only version source. To publish a release:
|
|
188
|
+
|
|
189
|
+
1. Update `__version__` in `_version.py` and commit the release changes.
|
|
190
|
+
2. Push `main` and wait for CI to pass.
|
|
191
|
+
3. Run the **Create release** GitHub Actions workflow. With no override it
|
|
192
|
+
creates the `v<version>` tag, creates release notes, and dispatches the build
|
|
193
|
+
and PyPI publication workflow.
|
|
194
|
+
|
|
195
|
+
PyPI versions are immutable. Increment `_version.py` before publishing different
|
|
196
|
+
content.
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
GA Graph is distributed under the MIT License. See [LICENSE](LICENSE).
|
ga_graph-0.1.0/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# GA Graph
|
|
2
|
+
|
|
3
|
+
[](https://github.com/andreagemma/graph/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/ga-graph/)
|
|
5
|
+
[](https://pypi.org/project/ga-graph/)
|
|
6
|
+
|
|
7
|
+
GA Graph provides lightweight dictionary-backed graph containers, path
|
|
8
|
+
collections, turn classification helpers, and a link-based time-dependent
|
|
9
|
+
shortest-path router.
|
|
10
|
+
|
|
11
|
+
The PyPI distribution is named `ga-graph`; the import package is named `graph`.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
python -m pip install ga-graph
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Development and test tools are available as extras:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python -m pip install -e ".[test]"
|
|
23
|
+
python -m pip install -e ".[dev]"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from graph import Graph
|
|
30
|
+
|
|
31
|
+
network = Graph(total_time=60, delta_t=15)
|
|
32
|
+
network.add_node("A")
|
|
33
|
+
network.add_node("B")
|
|
34
|
+
network.add_link("ab", "A", "B", cost=5)
|
|
35
|
+
|
|
36
|
+
assert network.get_link("ab").i == "A"
|
|
37
|
+
assert network.get_node_degree("A", include_in_links=False) == 1
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Graphs
|
|
41
|
+
|
|
42
|
+
`Graph` stores nodes, directed links, and turns in dictionary-backed containers.
|
|
43
|
+
Each entity keeps a required identifier plus arbitrary extra attributes.
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from graph import ActionPolicy, Graph
|
|
47
|
+
|
|
48
|
+
network = Graph()
|
|
49
|
+
network.add_link(
|
|
50
|
+
"ab",
|
|
51
|
+
"A",
|
|
52
|
+
"B",
|
|
53
|
+
on_missing_node=ActionPolicy.REPLACE,
|
|
54
|
+
capacity=1200,
|
|
55
|
+
)
|
|
56
|
+
network.add_turn("ab_bc", "ab", "bc", on_missing_link=ActionPolicy.IGNORE)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Duplicate and missing references can be handled with `ActionPolicy.RAISE`,
|
|
60
|
+
`WARN`, `IGNORE`, `REPLACE`, or `SKIP`, depending on the method.
|
|
61
|
+
|
|
62
|
+
## Paths
|
|
63
|
+
|
|
64
|
+
`Path` stores a source, target, departure time, optional mode, link sequence, and
|
|
65
|
+
cumulative costs. `PathList` stores one path per `(source, target, t_start,
|
|
66
|
+
mode)` key. `KPathList` stores multiple ranked paths for the same key.
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from graph import KPathList, Path
|
|
70
|
+
|
|
71
|
+
paths = KPathList()
|
|
72
|
+
paths.add_path(Path("A", "C", 0, links=["ab", "bc"], costs=[5, 9], mode="car"))
|
|
73
|
+
paths.add_path(Path("A", "C", 0, links=["ac"], costs=[12], mode="car"))
|
|
74
|
+
|
|
75
|
+
best = paths.path("A", "C", 0, "car", k=0)
|
|
76
|
+
second = paths.path("A", "C", 0, "car", k=1)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Time-Dependent Routing
|
|
80
|
+
|
|
81
|
+
`TimeDependentLinkBasedShortestPath` builds a dense routing view from a `Graph`.
|
|
82
|
+
Scalar costs are expanded across the graph time horizon; sequence costs are used
|
|
83
|
+
as piecewise-constant time profiles.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from graph import Graph, TimeDependentLinkBasedShortestPath
|
|
87
|
+
|
|
88
|
+
network = Graph(total_time=60, delta_t=15)
|
|
89
|
+
for node in ["A", "B", "C"]:
|
|
90
|
+
network.add_node(node, cost=0)
|
|
91
|
+
|
|
92
|
+
network.add_link("ab", "A", "B", cost=1)
|
|
93
|
+
network.add_link("bc", "B", "C", cost=1)
|
|
94
|
+
network.add_link("ac", "A", "C", cost=10)
|
|
95
|
+
|
|
96
|
+
router = TimeDependentLinkBasedShortestPath.from_graph(network, link_cost_field="cost")
|
|
97
|
+
path = router.shortest_paths("A", "C").path("A", "C", 0, None)
|
|
98
|
+
|
|
99
|
+
assert path.get_links() == ("ab", "bc")
|
|
100
|
+
assert path["tot_cost"] == 2
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The router supports optional mode fields, node costs, turn costs, and prohibited
|
|
104
|
+
turn fields.
|
|
105
|
+
|
|
106
|
+
## API Summary
|
|
107
|
+
|
|
108
|
+
- `Graph(t0=0, total_time=60, delta_t=15, **kwargs)`
|
|
109
|
+
- `Graph.add_node(idx, on_existing=ActionPolicy.RAISE, **kwargs)`
|
|
110
|
+
- `Graph.add_link(idx, i, j, on_existing=..., on_missing_node=..., **kwargs)`
|
|
111
|
+
- `Graph.add_turn(idx, in_link, out_link, on_existing=..., on_missing_link=..., **kwargs)`
|
|
112
|
+
- `Graph.get_node(idx)`, `Graph.get_link(idx)`, `Graph.get_turn(idx)`
|
|
113
|
+
- `Graph.remove_node(idx, cascade=False)`, `Graph.remove_link(idx, cascade=False)`
|
|
114
|
+
- `Graph.remove_redundants()`
|
|
115
|
+
- `Path(source, target, t_start, links=None, costs=None, mode=None, ...)`
|
|
116
|
+
- `PathList()`
|
|
117
|
+
- `KPathList()`
|
|
118
|
+
- `TurnType.parse(value)` and `TurnType.classify_turn(...)`
|
|
119
|
+
- `TimeDependentLinkBasedShortestPath.from_graph(graph, ...)`
|
|
120
|
+
- `TimeDependentLinkBasedShortestPath.shortest_paths(source, targets=None, t_start=0)`
|
|
121
|
+
|
|
122
|
+
## Development
|
|
123
|
+
|
|
124
|
+
GA Graph supports Python 3.10 and newer.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
python -m pip install -e ".[dev]"
|
|
128
|
+
python -m compileall -q src
|
|
129
|
+
python -m pytest --cov=graph --cov-report=term-missing
|
|
130
|
+
ruff format --check .
|
|
131
|
+
ruff check .
|
|
132
|
+
mypy
|
|
133
|
+
python -m pip check
|
|
134
|
+
python -m build
|
|
135
|
+
python -m twine check dist/*
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## GitHub Repository Setup
|
|
139
|
+
|
|
140
|
+
This project is prepared for the future repository `andreagemma/graph`.
|
|
141
|
+
|
|
142
|
+
1. Create the empty repository on GitHub.
|
|
143
|
+
2. Initialize the local repository if needed and push the project to `main`.
|
|
144
|
+
3. Confirm the CI workflow passes on GitHub.
|
|
145
|
+
4. Configure the PyPI Trusted Publisher for project `ga-graph`, owner
|
|
146
|
+
`andreagemma`, repository `graph`, workflow `release.yml`, and environment
|
|
147
|
+
`pypi`.
|
|
148
|
+
|
|
149
|
+
## Releases
|
|
150
|
+
|
|
151
|
+
`src/graph/_version.py` is the only version source. To publish a release:
|
|
152
|
+
|
|
153
|
+
1. Update `__version__` in `_version.py` and commit the release changes.
|
|
154
|
+
2. Push `main` and wait for CI to pass.
|
|
155
|
+
3. Run the **Create release** GitHub Actions workflow. With no override it
|
|
156
|
+
creates the `v<version>` tag, creates release notes, and dispatches the build
|
|
157
|
+
and PyPI publication workflow.
|
|
158
|
+
|
|
159
|
+
PyPI versions are immutable. Increment `_version.py` before publishing different
|
|
160
|
+
content.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
GA Graph is distributed under the MIT License. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## `Graph`
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
Graph(t0=0, total_time=60, delta_t=15, **kwargs)
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Stores nodes, directed links, and turns. Nodes, links, and turns are dictionary
|
|
10
|
+
subclasses, so custom attributes can be attached directly.
|
|
11
|
+
|
|
12
|
+
Main methods:
|
|
13
|
+
|
|
14
|
+
- `add_node(idx, on_existing=ActionPolicy.RAISE, **kwargs)`
|
|
15
|
+
- `add_link(idx, i, j, on_existing=..., on_missing_node=..., **kwargs)`
|
|
16
|
+
- `add_turn(idx, in_link, out_link, on_existing=..., on_missing_link=..., **kwargs)`
|
|
17
|
+
- `get_node(idx)`, `get_link(idx)`, `get_turn(idx)`
|
|
18
|
+
- `get_all_nodes()`, `get_all_links()`, `get_all_turns()`
|
|
19
|
+
- `remove_node(idx, cascade=False)`, `remove_link(idx, cascade=False)`
|
|
20
|
+
- `remove_redundants()`
|
|
21
|
+
- `resize_attributes(new_total_time=None, new_delta_t=None)`
|
|
22
|
+
|
|
23
|
+
## `Path`, `PathList`, and `KPathList`
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
Path(source, target, t_start, links=None, costs=None, tot_cost=0.0, mode=None)
|
|
27
|
+
PathList()
|
|
28
|
+
KPathList()
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`Path` stores the labels and cumulative costs for a route. `PathList` keeps one
|
|
32
|
+
path per `(source, target, t_start, mode)` key. `KPathList` keeps multiple
|
|
33
|
+
k-ranked paths for the same key.
|
|
34
|
+
|
|
35
|
+
Main methods:
|
|
36
|
+
|
|
37
|
+
- `Path.key()`
|
|
38
|
+
- `Path.get_links()`
|
|
39
|
+
- `Path.get_costs()`
|
|
40
|
+
- `Path.has_link(id_link)`
|
|
41
|
+
- `Path.counts_link(id_link)`
|
|
42
|
+
- `PathList.add_path(path)`
|
|
43
|
+
- `PathList.path(source, target, t_start=0, mode=None)`
|
|
44
|
+
- `KPathList.add_path(path, k=None)`
|
|
45
|
+
- `KPathList.path(source, target, t_start=None, mode=None, k=0)`
|
|
46
|
+
- `KPathList.paths(source, target, t_start, mode=None)`
|
|
47
|
+
|
|
48
|
+
## `TurnType`
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
TurnType.parse(value)
|
|
52
|
+
TurnType.classify_turn(in_edge_geometry, out_edge_geometry, angles=(30, 60, 120, 150))
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Provides semantic labels for straight, left, right, sharp, and U-turn
|
|
56
|
+
movements. Geometries must expose a `.coords` sequence.
|
|
57
|
+
|
|
58
|
+
## `TimeDependentLinkBasedShortestPath`
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
TimeDependentLinkBasedShortestPath.from_graph(graph, ...)
|
|
62
|
+
router.shortest_paths(source, targets=None, t_start=0)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Builds a dense link-based routing view from `Graph`. It supports scalar or
|
|
66
|
+
sequence cost fields on nodes, links, and turns, mode filters, and prohibited
|
|
67
|
+
turn fields.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# GA Graph Documentation
|
|
2
|
+
|
|
3
|
+
GA Graph contains lightweight graph containers, path collections, turn helpers,
|
|
4
|
+
and a link-based time-dependent shortest-path router.
|
|
5
|
+
|
|
6
|
+
- See [API Reference](api.md) for the public classes and methods.
|
|
7
|
+
- See the project [README](../README.md) for installation, quick start, and
|
|
8
|
+
release instructions.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ga-graph"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Lightweight graph, turn, path, and time-dependent routing utilities."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "GA Graph contributors" }
|
|
15
|
+
]
|
|
16
|
+
keywords = ["ga-graph", "graph", "routing", "shortest-path", "transport-network"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Typing :: Typed"
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"dill>=0.3.8"
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
test = [
|
|
35
|
+
"pytest>=8.0",
|
|
36
|
+
"pytest-cov>=5.0"
|
|
37
|
+
]
|
|
38
|
+
dev = [
|
|
39
|
+
"build>=1.2",
|
|
40
|
+
"mypy>=1.10",
|
|
41
|
+
"pytest>=8.0",
|
|
42
|
+
"pytest-cov>=5.0",
|
|
43
|
+
"ruff>=0.5",
|
|
44
|
+
"twine>=5.1"
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Documentation = "https://github.com/andreagemma/graph#readme"
|
|
49
|
+
Issues = "https://github.com/andreagemma/graph/issues"
|
|
50
|
+
Source = "https://github.com/andreagemma/graph"
|
|
51
|
+
|
|
52
|
+
[tool.setuptools]
|
|
53
|
+
package-dir = {"" = "src"}
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.packages.find]
|
|
56
|
+
where = ["src"]
|
|
57
|
+
|
|
58
|
+
[tool.setuptools.package-data]
|
|
59
|
+
graph = ["py.typed"]
|
|
60
|
+
|
|
61
|
+
[tool.setuptools.dynamic]
|
|
62
|
+
version = {attr = "graph._version.__version__"}
|
|
63
|
+
|
|
64
|
+
[tool.pytest.ini_options]
|
|
65
|
+
testpaths = ["tests"]
|
|
66
|
+
addopts = "-ra --strict-markers"
|
|
67
|
+
|
|
68
|
+
[tool.coverage.run]
|
|
69
|
+
branch = true
|
|
70
|
+
source = ["graph"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 100
|
|
74
|
+
target-version = "py310"
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint]
|
|
77
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
78
|
+
|
|
79
|
+
[tool.mypy]
|
|
80
|
+
python_version = "3.10"
|
|
81
|
+
files = ["src"]
|
|
82
|
+
warn_unused_configs = true
|
|
83
|
+
check_untyped_defs = true
|
|
84
|
+
follow_imports = "skip"
|
|
85
|
+
no_site_packages = true
|
|
86
|
+
ignore_missing_imports = true
|
ga_graph-0.1.0/setup.cfg
ADDED