scgraph 2.2.0__tar.gz → 2.4.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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: scgraph
3
- Version: 2.2.0
3
+ Version: 2.4.0
4
4
  Summary: Determine an approximate route between two points on earth.
5
5
  Author-email: Connor Makowski <conmak@mit.edu>
6
6
  Project-URL: Homepage, https://github.com/connor-makowski/scgraph
@@ -9,13 +9,15 @@ Project-URL: Documentation, https://connor-makowski.github.io/scgraph/core.html
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.6
12
+ Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
+ Dynamic: license-file
15
16
 
16
17
  # scgraph
17
18
  [![PyPI version](https://badge.fury.io/py/scgraph.svg)](https://badge.fury.io/py/scgraph)
18
19
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
20
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/scgraph.svg?label=PyPI%20downloads)](https://pypi.org/project/scgraph/)
19
21
 
20
22
  Supply chain graph package for Python
21
23
 
@@ -52,12 +54,16 @@ Low Level: https://connor-makowski.github.io/scgraph/scgraph/core.html
52
54
  - Antimeridian support
53
55
  - Arbitrary start and end points
54
56
  - Arbitrary network data sets
57
+ - Grid based graphs
58
+ - Cached shortest path calculations for very fast repetative calculations to or from the same point in a graph.
59
+ - Note: Geographs are not yet supported for this feature
55
60
 
56
61
 
57
-
58
62
  ## Setup
59
63
 
60
- Make sure you have Python 3.6.x (or higher) installed on your system. You can download it [here](https://www.python.org/downloads/).
64
+ Make sure you have Python 3.10.x (or higher) installed on your system. You can download it [here](https://www.python.org/downloads/).
65
+
66
+ Note: Support for python3.6-python3.9 is available up to version 2.2.0.
61
67
 
62
68
  ## Installation
63
69
 
@@ -67,7 +73,10 @@ pip install scgraph
67
73
 
68
74
  ## Use with Google Colab
69
75
 
70
- See the example [here](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/example.ipynb)
76
+ - [Getting Started](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/getting_started.ipynb)
77
+ - [Creating A Multi Path Geojson](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/multi_path_geojson.ipynb)
78
+ - [Modifying A Geograph](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/geograph_modifications.ipynb)
79
+
71
80
 
72
81
  # Getting Started
73
82
 
@@ -101,7 +110,7 @@ In the above example, the `output` variable is a dictionary with three keys: `le
101
110
  - `ft` (feet)
102
111
  - `coordinate_path`: A list of lists [`latitude`,`longitude`] that make up the shortest path
103
112
 
104
- For more examples including viewing the output on a map, see the [example notebook](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/example.ipynb).
113
+ For more examples including viewing the output on a map, see the [example notebook](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/getting_started.ipynb).
105
114
 
106
115
  ## Included GeoGraphs
107
116
 
@@ -136,6 +145,49 @@ For more examples including viewing the output on a map, see the [example notebo
136
145
  - Use: `from scgraph_data.world_highways import world_highways_geograph`
137
146
  - See: [scgraph_data](https://github.com/connor-makowski/scgraph_data) for more information and all available geographs.
138
147
 
148
+ ## GridGraph usage
149
+
150
+ Example:
151
+ - Create a grid of 20x100 cells.
152
+ - This creates a grid based graph with connections to all 8 neighbors for each grid item.
153
+ - Each grid item has 4 cardinal connections at length 1 and 4 diagonal connections at length sqrt(2)
154
+ - Create a wall from (10,5) to (10,99).
155
+ - This would foce any path to go to the bottom of the graph to get around the wall.
156
+ - Get the shortest path between (2,10) and (18,10)
157
+ - Note: The length of this path should be 16 without the wall and 20.9704 with the wall.
158
+
159
+ ```py
160
+ from scgraph import GridGraph
161
+
162
+ x_size = 20
163
+ y_size = 20
164
+ blocks = [(10, i) for i in range(5, y_size)]
165
+
166
+ # Create the GridGraph object
167
+ gridGraph = GridGraph(
168
+ x_size=x_size,
169
+ y_size=y_size,
170
+ blocks=blocks,
171
+ add_exterior_walls=True,
172
+ )
173
+
174
+ # Solve the shortest path between two points
175
+ output = gridGraph.get_shortest_path(
176
+ origin_node={"x": 2, "y": 10},
177
+ destination_node={"x": 18, "y": 10},
178
+ # Optional: Specify the output coodinate format (default is 'list_of_dicts)
179
+ output_coordinate_path="list_of_lists",
180
+ # Optional: Cache the origin point spanning_tree for faster calculations on future calls
181
+ cache=True,
182
+ # Optional: Specify the node to cache the spanning tree for (default is the origin node)
183
+ # Note: This first call will be slower, but future calls using this origin node will be substantially faster
184
+ cache_for="origin",
185
+ )
186
+
187
+ print(output)
188
+ #=> {'length': 20.9704, 'coordinate_path': [[2, 10], [3, 9], [4, 8], [5, 8], [6, 7], [7, 6], [8, 5], [9, 4], [10, 4], [11, 4], [12, 5], [13, 6], [14, 7], [15, 7], [16, 8], [17, 9], [18, 10]]}
189
+ ```
190
+
139
191
  ## Advanced Usage
140
192
 
141
193
  Using `scgraph_data` geographs:
@@ -165,7 +217,7 @@ output = marnet_geograph.get_shortest_path(
165
217
  get_line_path(output, filename='output.geojson')
166
218
  ```
167
219
 
168
- Modify an existing geograph: See the notebook [here](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/example_making_modifications.ipynb)
220
+ Modify an existing geograph: See the notebook [here](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/geograph_modifications.ipynb)
169
221
 
170
222
 
171
223
  You can specify your own custom graphs for direct access to the solving algorithms. This requires the use of the low level `Graph` class
@@ -173,9 +225,9 @@ You can specify your own custom graphs for direct access to the solving algorith
173
225
  ```py
174
226
  from scgraph import Graph
175
227
 
176
- # Define a graph
228
+ # Define an arbitrary graph
177
229
  # See the graph definitions here:
178
- # https://connor-makowski.github.io/scgraph/scgraph/core.html
230
+ # https://connor-makowski.github.io/scgraph/scgraph/core.html#GeoGraph
179
231
  graph = [
180
232
  {1: 5, 2: 1},
181
233
  {0: 5, 2: 2, 3: 1},
@@ -200,25 +252,67 @@ from scgraph import GeoGraph
200
252
 
201
253
  # Define nodes
202
254
  # See the nodes definitions here:
203
- # https://connor-makowski.github.io/scgraph/scgraph/core.html
255
+ # https://connor-makowski.github.io/scgraph/scgraph/core.html#GeoGraph
204
256
  nodes = [
205
- [0,0],
206
- [0,1],
207
- [1,0],
208
- [1,1],
209
- [1,2],
210
- [2,1]
257
+ # London
258
+ [51.5074, -0.1278],
259
+ # Paris
260
+ [48.8566, 2.3522],
261
+ # Berlin
262
+ [52.5200, 13.4050],
263
+ # Rome
264
+ [41.9028, 12.4964],
265
+ # Madrid
266
+ [40.4168, -3.7038],
267
+ # Lisbon
268
+ [38.7223, -9.1393]
211
269
  ]
212
270
  # Define a graph
213
271
  # See the graph definitions here:
214
- # https://connor-makowski.github.io/scgraph/scgraph/core.html
272
+ # https://connor-makowski.github.io/scgraph/scgraph/core.html#GeoGraph
215
273
  graph = [
216
- {1: 5, 2: 1},
217
- {0: 5, 2: 2, 3: 1},
218
- {0: 1, 1: 2, 3: 4, 4: 8},
219
- {1: 1, 2: 4, 4: 3, 5: 6},
220
- {2: 8, 3: 3},
221
- {3: 6}
274
+ # From London
275
+ {
276
+ # To Paris
277
+ 1: 311,
278
+ },
279
+ # From Paris
280
+ {
281
+ # To London
282
+ 0: 311,
283
+ # To Berlin
284
+ 2: 878,
285
+ # To Rome
286
+ 3: 1439,
287
+ # To Madrid
288
+ 4: 1053
289
+ },
290
+ # From Berlin
291
+ {
292
+ # To Paris
293
+ 1: 878,
294
+ # To Rome
295
+ 3: 1181,
296
+ },
297
+ # From Rome
298
+ {
299
+ # To Paris
300
+ 1: 1439,
301
+ # To Berlin
302
+ 2: 1181,
303
+ },
304
+ # From Madrid
305
+ {
306
+ # To Paris
307
+ 1: 1053,
308
+ # To Lisbon
309
+ 5: 623
310
+ },
311
+ # From Lisbon
312
+ {
313
+ # To Madrid
314
+ 4: 623
315
+ }
222
316
  ]
223
317
 
224
318
  # Create a GeoGraph object
@@ -231,24 +325,49 @@ my_geograph.validate_graph()
231
325
  my_geograph.validate_nodes()
232
326
 
233
327
  # Get the shortest path between two points
328
+ # In this case, Birmingham England and Zaragoza Spain
329
+ # Since Birmingham and Zaragoza are not in the graph,
330
+ # the algorithm will add them into the graph.
331
+ # See: https://connor-makowski.github.io/scgraph/scgraph/core.html#GeoGraph.get_shortest_path
332
+ # Expected output would be to go from
333
+ # Birmingham -> London -> Paris -> Madrid -> Zaragoza
334
+
234
335
  output = my_geograph.get_shortest_path(
235
- origin_node = {'latitude': 0, 'longitude': 0},
236
- destination_node = {'latitude': 2, 'longitude': 1}
336
+ # Birmingham England
337
+ origin_node = {'latitude': 52.4862, 'longitude': -1.8904},
338
+ # Zaragoza Spain
339
+ destination_node = {'latitude': 41.6488, 'longitude': -0.8891}
237
340
  )
238
- #=>
341
+ print(output)
239
342
  # {
240
- # "coordinate_path": [
241
- # [0,0],
242
- # [0,0],
243
- # [1,0],
244
- # [0,1],
245
- # [1,1],
246
- # [2,1],
247
- # [2,1]
248
- # ],
249
- # "length": 10
343
+ # 'length': 1799.4323,
344
+ # 'coordinate_path': [
345
+ # [52.4862, -1.8904],
346
+ # [51.5074, -0.1278],
347
+ # [48.8566, 2.3522],
348
+ # [40.4168, -3.7038],
349
+ # [41.6488, -0.8891]
350
+ # ]
250
351
  # }
352
+
251
353
  ```
252
354
 
355
+ # Development
356
+ ## Running Tests, Prettifying Code, and Updating Docs
357
+
358
+ Make sure Docker is installed and running on a Unix system (Linux, MacOS, WSL2).
359
+
360
+ - Create a docker container and drop into a shell
361
+ - `./run.sh`
362
+ - Run all tests (see ./utils/test.sh)
363
+ - `./run.sh test`
364
+ - Prettify the code (see ./utils/prettify.sh)
365
+ - `./run.sh prettify`
366
+ - Update the docs (see ./utils/docs.sh)
367
+ - `./run.sh docs`
368
+
369
+ - Note: You can and should modify the `Dockerfile` to test different python versions.
370
+
371
+
253
372
  ## Attributions and Thanks
254
373
  Originally inspired by [searoute](https://github.com/genthalili/searoute-py) including the use of one of their [datasets](https://github.com/genthalili/searoute-py/blob/main/searoute/data/marnet_densified_v2_old.geojson) that has been modified to work properly with this package.
@@ -1,6 +1,7 @@
1
1
  # scgraph
2
2
  [![PyPI version](https://badge.fury.io/py/scgraph.svg)](https://badge.fury.io/py/scgraph)
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/scgraph.svg?label=PyPI%20downloads)](https://pypi.org/project/scgraph/)
4
5
 
5
6
  Supply chain graph package for Python
6
7
 
@@ -37,12 +38,16 @@ Low Level: https://connor-makowski.github.io/scgraph/scgraph/core.html
37
38
  - Antimeridian support
38
39
  - Arbitrary start and end points
39
40
  - Arbitrary network data sets
41
+ - Grid based graphs
42
+ - Cached shortest path calculations for very fast repetative calculations to or from the same point in a graph.
43
+ - Note: Geographs are not yet supported for this feature
40
44
 
41
45
 
42
-
43
46
  ## Setup
44
47
 
45
- Make sure you have Python 3.6.x (or higher) installed on your system. You can download it [here](https://www.python.org/downloads/).
48
+ Make sure you have Python 3.10.x (or higher) installed on your system. You can download it [here](https://www.python.org/downloads/).
49
+
50
+ Note: Support for python3.6-python3.9 is available up to version 2.2.0.
46
51
 
47
52
  ## Installation
48
53
 
@@ -52,7 +57,10 @@ pip install scgraph
52
57
 
53
58
  ## Use with Google Colab
54
59
 
55
- See the example [here](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/example.ipynb)
60
+ - [Getting Started](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/getting_started.ipynb)
61
+ - [Creating A Multi Path Geojson](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/multi_path_geojson.ipynb)
62
+ - [Modifying A Geograph](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/geograph_modifications.ipynb)
63
+
56
64
 
57
65
  # Getting Started
58
66
 
@@ -86,7 +94,7 @@ In the above example, the `output` variable is a dictionary with three keys: `le
86
94
  - `ft` (feet)
87
95
  - `coordinate_path`: A list of lists [`latitude`,`longitude`] that make up the shortest path
88
96
 
89
- For more examples including viewing the output on a map, see the [example notebook](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/example.ipynb).
97
+ For more examples including viewing the output on a map, see the [example notebook](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/getting_started.ipynb).
90
98
 
91
99
  ## Included GeoGraphs
92
100
 
@@ -121,6 +129,49 @@ For more examples including viewing the output on a map, see the [example notebo
121
129
  - Use: `from scgraph_data.world_highways import world_highways_geograph`
122
130
  - See: [scgraph_data](https://github.com/connor-makowski/scgraph_data) for more information and all available geographs.
123
131
 
132
+ ## GridGraph usage
133
+
134
+ Example:
135
+ - Create a grid of 20x100 cells.
136
+ - This creates a grid based graph with connections to all 8 neighbors for each grid item.
137
+ - Each grid item has 4 cardinal connections at length 1 and 4 diagonal connections at length sqrt(2)
138
+ - Create a wall from (10,5) to (10,99).
139
+ - This would foce any path to go to the bottom of the graph to get around the wall.
140
+ - Get the shortest path between (2,10) and (18,10)
141
+ - Note: The length of this path should be 16 without the wall and 20.9704 with the wall.
142
+
143
+ ```py
144
+ from scgraph import GridGraph
145
+
146
+ x_size = 20
147
+ y_size = 20
148
+ blocks = [(10, i) for i in range(5, y_size)]
149
+
150
+ # Create the GridGraph object
151
+ gridGraph = GridGraph(
152
+ x_size=x_size,
153
+ y_size=y_size,
154
+ blocks=blocks,
155
+ add_exterior_walls=True,
156
+ )
157
+
158
+ # Solve the shortest path between two points
159
+ output = gridGraph.get_shortest_path(
160
+ origin_node={"x": 2, "y": 10},
161
+ destination_node={"x": 18, "y": 10},
162
+ # Optional: Specify the output coodinate format (default is 'list_of_dicts)
163
+ output_coordinate_path="list_of_lists",
164
+ # Optional: Cache the origin point spanning_tree for faster calculations on future calls
165
+ cache=True,
166
+ # Optional: Specify the node to cache the spanning tree for (default is the origin node)
167
+ # Note: This first call will be slower, but future calls using this origin node will be substantially faster
168
+ cache_for="origin",
169
+ )
170
+
171
+ print(output)
172
+ #=> {'length': 20.9704, 'coordinate_path': [[2, 10], [3, 9], [4, 8], [5, 8], [6, 7], [7, 6], [8, 5], [9, 4], [10, 4], [11, 4], [12, 5], [13, 6], [14, 7], [15, 7], [16, 8], [17, 9], [18, 10]]}
173
+ ```
174
+
124
175
  ## Advanced Usage
125
176
 
126
177
  Using `scgraph_data` geographs:
@@ -150,7 +201,7 @@ output = marnet_geograph.get_shortest_path(
150
201
  get_line_path(output, filename='output.geojson')
151
202
  ```
152
203
 
153
- Modify an existing geograph: See the notebook [here](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/example_making_modifications.ipynb)
204
+ Modify an existing geograph: See the notebook [here](https://colab.research.google.com/github/connor-makowski/scgraph/blob/main/examples/geograph_modifications.ipynb)
154
205
 
155
206
 
156
207
  You can specify your own custom graphs for direct access to the solving algorithms. This requires the use of the low level `Graph` class
@@ -158,9 +209,9 @@ You can specify your own custom graphs for direct access to the solving algorith
158
209
  ```py
159
210
  from scgraph import Graph
160
211
 
161
- # Define a graph
212
+ # Define an arbitrary graph
162
213
  # See the graph definitions here:
163
- # https://connor-makowski.github.io/scgraph/scgraph/core.html
214
+ # https://connor-makowski.github.io/scgraph/scgraph/core.html#GeoGraph
164
215
  graph = [
165
216
  {1: 5, 2: 1},
166
217
  {0: 5, 2: 2, 3: 1},
@@ -185,25 +236,67 @@ from scgraph import GeoGraph
185
236
 
186
237
  # Define nodes
187
238
  # See the nodes definitions here:
188
- # https://connor-makowski.github.io/scgraph/scgraph/core.html
239
+ # https://connor-makowski.github.io/scgraph/scgraph/core.html#GeoGraph
189
240
  nodes = [
190
- [0,0],
191
- [0,1],
192
- [1,0],
193
- [1,1],
194
- [1,2],
195
- [2,1]
241
+ # London
242
+ [51.5074, -0.1278],
243
+ # Paris
244
+ [48.8566, 2.3522],
245
+ # Berlin
246
+ [52.5200, 13.4050],
247
+ # Rome
248
+ [41.9028, 12.4964],
249
+ # Madrid
250
+ [40.4168, -3.7038],
251
+ # Lisbon
252
+ [38.7223, -9.1393]
196
253
  ]
197
254
  # Define a graph
198
255
  # See the graph definitions here:
199
- # https://connor-makowski.github.io/scgraph/scgraph/core.html
256
+ # https://connor-makowski.github.io/scgraph/scgraph/core.html#GeoGraph
200
257
  graph = [
201
- {1: 5, 2: 1},
202
- {0: 5, 2: 2, 3: 1},
203
- {0: 1, 1: 2, 3: 4, 4: 8},
204
- {1: 1, 2: 4, 4: 3, 5: 6},
205
- {2: 8, 3: 3},
206
- {3: 6}
258
+ # From London
259
+ {
260
+ # To Paris
261
+ 1: 311,
262
+ },
263
+ # From Paris
264
+ {
265
+ # To London
266
+ 0: 311,
267
+ # To Berlin
268
+ 2: 878,
269
+ # To Rome
270
+ 3: 1439,
271
+ # To Madrid
272
+ 4: 1053
273
+ },
274
+ # From Berlin
275
+ {
276
+ # To Paris
277
+ 1: 878,
278
+ # To Rome
279
+ 3: 1181,
280
+ },
281
+ # From Rome
282
+ {
283
+ # To Paris
284
+ 1: 1439,
285
+ # To Berlin
286
+ 2: 1181,
287
+ },
288
+ # From Madrid
289
+ {
290
+ # To Paris
291
+ 1: 1053,
292
+ # To Lisbon
293
+ 5: 623
294
+ },
295
+ # From Lisbon
296
+ {
297
+ # To Madrid
298
+ 4: 623
299
+ }
207
300
  ]
208
301
 
209
302
  # Create a GeoGraph object
@@ -216,24 +309,49 @@ my_geograph.validate_graph()
216
309
  my_geograph.validate_nodes()
217
310
 
218
311
  # Get the shortest path between two points
312
+ # In this case, Birmingham England and Zaragoza Spain
313
+ # Since Birmingham and Zaragoza are not in the graph,
314
+ # the algorithm will add them into the graph.
315
+ # See: https://connor-makowski.github.io/scgraph/scgraph/core.html#GeoGraph.get_shortest_path
316
+ # Expected output would be to go from
317
+ # Birmingham -> London -> Paris -> Madrid -> Zaragoza
318
+
219
319
  output = my_geograph.get_shortest_path(
220
- origin_node = {'latitude': 0, 'longitude': 0},
221
- destination_node = {'latitude': 2, 'longitude': 1}
320
+ # Birmingham England
321
+ origin_node = {'latitude': 52.4862, 'longitude': -1.8904},
322
+ # Zaragoza Spain
323
+ destination_node = {'latitude': 41.6488, 'longitude': -0.8891}
222
324
  )
223
- #=>
325
+ print(output)
224
326
  # {
225
- # "coordinate_path": [
226
- # [0,0],
227
- # [0,0],
228
- # [1,0],
229
- # [0,1],
230
- # [1,1],
231
- # [2,1],
232
- # [2,1]
233
- # ],
234
- # "length": 10
327
+ # 'length': 1799.4323,
328
+ # 'coordinate_path': [
329
+ # [52.4862, -1.8904],
330
+ # [51.5074, -0.1278],
331
+ # [48.8566, 2.3522],
332
+ # [40.4168, -3.7038],
333
+ # [41.6488, -0.8891]
334
+ # ]
235
335
  # }
336
+
236
337
  ```
237
338
 
339
+ # Development
340
+ ## Running Tests, Prettifying Code, and Updating Docs
341
+
342
+ Make sure Docker is installed and running on a Unix system (Linux, MacOS, WSL2).
343
+
344
+ - Create a docker container and drop into a shell
345
+ - `./run.sh`
346
+ - Run all tests (see ./utils/test.sh)
347
+ - `./run.sh test`
348
+ - Prettify the code (see ./utils/prettify.sh)
349
+ - `./run.sh prettify`
350
+ - Update the docs (see ./utils/docs.sh)
351
+ - `./run.sh docs`
352
+
353
+ - Note: You can and should modify the `Dockerfile` to test different python versions.
354
+
355
+
238
356
  ## Attributions and Thanks
239
357
  Originally inspired by [searoute](https://github.com/genthalili/searoute-py) including the use of one of their [datasets](https://github.com/genthalili/searoute-py/blob/main/searoute/data/marnet_densified_v2_old.geojson) that has been modified to work properly with this package.
@@ -12,13 +12,13 @@ build-backend = "setuptools.build_meta"
12
12
 
13
13
  [project]
14
14
  name = "scgraph"
15
- version = "2.2.0"
15
+ version = "2.4.0"
16
16
  description = "Determine an approximate route between two points on earth."
17
17
  authors = [
18
18
  {name="Connor Makowski", email="conmak@mit.edu"}
19
19
  ]
20
20
  readme = "README.md"
21
- requires-python = ">=3.6"
21
+ requires-python = ">=3.10"
22
22
  classifiers = [
23
23
  "Programming Language :: Python :: 3",
24
24
  'License :: OSI Approved :: MIT License',