fastgpx 0.1.0__cp311-cp311-win_amd64.whl

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.
fastgpx/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ # Re-export the C extension module to make it available as fastgpx instead of fastgpx.fastgpx.
2
+ from .fastgpx import * # type: ignore
3
+
4
+ # Needed for sphinx autosummary to pick up the re-exported C extension module.
5
+ __all__ = [name for name in dir(fastgpx) if not name.startswith('_')] # type: ignore
fastgpx/__init__.pyi ADDED
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+ from fastgpx.fastgpx import Bounds
3
+ from fastgpx.fastgpx import Gpx
4
+ from fastgpx.fastgpx import LatLong
5
+ from fastgpx.fastgpx import Segment
6
+ from fastgpx.fastgpx import TimeBounds
7
+ from fastgpx.fastgpx import Track
8
+ from fastgpx.fastgpx import geo
9
+ from fastgpx.fastgpx import parse
10
+ from fastgpx.fastgpx import polyline
11
+ from . import fastgpx
12
+ __all__ = ['Bounds', 'Gpx', 'LatLong', 'Segment', 'TimeBounds', 'Track', 'fastgpx', 'geo', 'parse', 'polyline']
@@ -0,0 +1,128 @@
1
+ from __future__ import annotations
2
+ import datetime
3
+ import typing
4
+ from . import geo
5
+ from . import polyline
6
+ __all__ = ['Bounds', 'Gpx', 'LatLong', 'Segment', 'TimeBounds', 'Track', 'geo', 'parse', 'polyline']
7
+ class Bounds:
8
+ max: LatLong | None
9
+ min: LatLong | None
10
+ @typing.overload
11
+ def __init__(self) -> None:
12
+ ...
13
+ @typing.overload
14
+ def __init__(self, min: LatLong, max: LatLong) -> None:
15
+ ...
16
+ @typing.overload
17
+ def __init__(self, min: tuple[float, float], max: tuple[float, float]) -> None:
18
+ ...
19
+ @typing.overload
20
+ def add(self, location: LatLong) -> None:
21
+ ...
22
+ @typing.overload
23
+ def add(self, bounds: Bounds) -> None:
24
+ ...
25
+ def is_empty(self) -> bool:
26
+ ...
27
+ def max_bounds(self, bounds: Bounds) -> Bounds:
28
+ ...
29
+ @property
30
+ def max_latitude(self) -> float | None:
31
+ ...
32
+ @max_latitude.setter
33
+ def max_latitude(self, arg1: float) -> None:
34
+ ...
35
+ @property
36
+ def max_longitude(self) -> float | None:
37
+ ...
38
+ @max_longitude.setter
39
+ def max_longitude(self, arg1: float) -> None:
40
+ ...
41
+ @property
42
+ def min_latitude(self) -> float | None:
43
+ ...
44
+ @min_latitude.setter
45
+ def min_latitude(self, arg1: float) -> None:
46
+ ...
47
+ @property
48
+ def min_longitude(self) -> float | None:
49
+ ...
50
+ @min_longitude.setter
51
+ def min_longitude(self, arg1: float) -> None:
52
+ ...
53
+ class Gpx:
54
+ tracks: list[Track]
55
+ def __init__(self) -> None:
56
+ ...
57
+ def bounds(self) -> Bounds:
58
+ ...
59
+ def get_bounds(self) -> Bounds:
60
+ ...
61
+ def get_time_bounds(self) -> TimeBounds:
62
+ ...
63
+ def length_2d(self) -> float:
64
+ ...
65
+ def length_3d(self) -> float:
66
+ ...
67
+ def time_bounds(self) -> TimeBounds:
68
+ ...
69
+ class LatLong:
70
+ elevation: float
71
+ latitude: float
72
+ longitude: float
73
+ @typing.overload
74
+ def __init__(self) -> None:
75
+ ...
76
+ @typing.overload
77
+ def __init__(self, latitude: float, longitude: float, elevation: float = 0.0) -> None:
78
+ ...
79
+ class Segment:
80
+ points: list[LatLong]
81
+ def __init__(self) -> None:
82
+ ...
83
+ def bounds(self) -> Bounds:
84
+ ...
85
+ def get_bounds(self) -> Bounds:
86
+ ...
87
+ def get_time_bounds(self) -> TimeBounds:
88
+ ...
89
+ def length_2d(self) -> float:
90
+ ...
91
+ def length_3d(self) -> float:
92
+ ...
93
+ def time_bounds(self) -> TimeBounds:
94
+ ...
95
+ class TimeBounds:
96
+ end_time: datetime.datetime | None
97
+ start_time: datetime.datetime | None
98
+ @typing.overload
99
+ def __init__(self) -> None:
100
+ ...
101
+ @typing.overload
102
+ def __init__(self, start_time: datetime.datetime | None, end_time: datetime.datetime | None) -> None:
103
+ ...
104
+ def is_empty(self) -> bool:
105
+ ...
106
+ class Track:
107
+ comment: str | None
108
+ description: str | None
109
+ name: str | None
110
+ number: int | None
111
+ segments: list[Segment]
112
+ type: str | None
113
+ def __init__(self) -> None:
114
+ ...
115
+ def bounds(self) -> Bounds:
116
+ ...
117
+ def get_bounds(self) -> Bounds:
118
+ ...
119
+ def get_time_bounds(self) -> TimeBounds:
120
+ ...
121
+ def length_2d(self) -> float:
122
+ ...
123
+ def length_3d(self) -> float:
124
+ ...
125
+ def time_bounds(self) -> TimeBounds:
126
+ ...
127
+ def parse(path: str) -> Gpx:
128
+ ...
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+ import fastgpx.fastgpx
3
+ __all__ = ['haversine', 'haversine_distance']
4
+ def haversine(latlong1: fastgpx.fastgpx.LatLong, latlong2: fastgpx.fastgpx.LatLong) -> float:
5
+ ...
6
+ def haversine_distance(latitude_1: float, longitude_1: float, latitude_2: float, longitude_2: float) -> float:
7
+ """
8
+ Compatibility with `gpxpy.geo.haversine_distance`
9
+ """
@@ -0,0 +1,54 @@
1
+ from __future__ import annotations
2
+ import fastgpx
3
+ import fastgpx.fastgpx
4
+ import typing
5
+ __all__ = ['Precision', 'decode', 'encode']
6
+ class Precision:
7
+ """
8
+ Members:
9
+
10
+ Five
11
+
12
+ Six
13
+ """
14
+ Five: typing.ClassVar[Precision] # value = <Precision.Five: 5>
15
+ Six: typing.ClassVar[Precision] # value = <Precision.Six: 6>
16
+ __members__: typing.ClassVar[dict[str, Precision]] # value = {'Five': <Precision.Five: 5>, 'Six': <Precision.Six: 6>}
17
+ def __eq__(self, other: typing.Any) -> bool:
18
+ ...
19
+ def __getstate__(self) -> int:
20
+ ...
21
+ def __hash__(self) -> int:
22
+ ...
23
+ def __index__(self) -> int:
24
+ ...
25
+ def __init__(self, value: int) -> None:
26
+ ...
27
+ def __int__(self) -> int:
28
+ ...
29
+ def __ne__(self, other: typing.Any) -> bool:
30
+ ...
31
+ def __repr__(self) -> str:
32
+ ...
33
+ def __setstate__(self, state: int) -> None:
34
+ ...
35
+ def __str__(self) -> str:
36
+ ...
37
+ @property
38
+ def name(self) -> str:
39
+ ...
40
+ @property
41
+ def value(self) -> int:
42
+ ...
43
+ @typing.overload
44
+ def decode(encoded: str, precision: Precision = fastgpx.polyline.Precision.Five) -> list[fastgpx.fastgpx.LatLong]:
45
+ ...
46
+ @typing.overload
47
+ def decode(locations: str, precision: int = 5) -> list[fastgpx.fastgpx.LatLong]:
48
+ ...
49
+ @typing.overload
50
+ def encode(locations: list[fastgpx.fastgpx.LatLong], precision: Precision = fastgpx.polyline.Precision.Five) -> str:
51
+ ...
52
+ @typing.overload
53
+ def encode(locations: list[fastgpx.fastgpx.LatLong], precision: int = 5) -> str:
54
+ ...
Binary file
fastgpx/py.typed ADDED
File without changes
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastgpx
3
+ Version: 0.1.0
4
+ Summary: An experimental Python library for parsing GPX files fast.
5
+ Keywords: gpx,parser,fast
6
+ Author: Thomas Thomassen
7
+ License-Expression: MIT
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: File Formats
11
+ Classifier: Operating System :: Microsoft :: Windows
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Project-URL: Documentation, https://thomthom.github.io/fastgpx/
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+
17
+ # fastgpx
18
+
19
+ An experimental Python library for parsing GPX files fast.
20
+
21
+ ```py
22
+ # Get the total length of the tracks in a GPX file:
23
+ import fastgpx
24
+
25
+ gpx = fastgpx.parse("example.gpx")
26
+ print(f'{gpx.length_2d()} m')
27
+ ```
28
+
29
+ ```py
30
+ # Iterate over GPX file:
31
+ import fastgpx
32
+
33
+ gpx = fastgpx.parse("example.gpx")
34
+ for track in gpx.tracks:
35
+ print(f'Track: {track.name}')
36
+ print(f'Distance: {track.length_2d()} m')
37
+ if not track.time_bounds.is_empty():
38
+ print(f'Time: {track.time_bounds().start_time} - {track.time_bounds().end_time}')
39
+ for segment in track.segments:
40
+ print(f'Segment: {segment.name}')
41
+ for point in segment.points:
42
+ print(f'Point: {point.latitude}, {point.longitude}')
43
+ ```
44
+
45
+ [Documentation](https://thomthom.github.io/fastgpx/)
46
+
47
+ ## GPX/XML Performance (Background)
48
+
49
+ `gpxpy` appear to be the most popular GPX library for Python.
50
+
51
+ `gpxpy` docs says that it uses `lxml` is available because it is faster than "`minidom`" (`etree`).
52
+ When benchmarking that seemed not to be the case. It appear that the stdlib XML library has gotten
53
+ much better since `gpxpy` was created.
54
+
55
+ Reference: Open ticket on making `etree` default:
56
+ https://github.com/tkrajina/gpxpy/issues/248
57
+
58
+ ## Benchmarks
59
+
60
+ Test machine:
61
+
62
+ * AMD Ryzen 7 5800 8-Core, 3.80 GHz
63
+ * 32 GB memory
64
+ * m2 SSD storage
65
+
66
+ ### gpxpy benchmarks
67
+
68
+ Comparing getting the distance of a GPX file using `gpxpy` vs manually extracting
69
+ the data using `xml_etree`, computing distance between points using `gpxpy`
70
+ distance functions.
71
+
72
+ #### gpxpy without `lxml`
73
+
74
+ ```
75
+ Running benchmark with 3 iterations...
76
+ gpxpy 5463041.784135511 meters
77
+ gpxpy 5463041.784135511 meters
78
+ gpxpy 5463041.784135511 meters
79
+ gpxpy: 11.497863 seconds (Average: 3.832621 seconds)
80
+ ```
81
+
82
+ #### gpxpy with `lxml`
83
+
84
+ ```
85
+ Running benchmark with 3 iterations...
86
+ gpxpy 5463041.784135511 meters
87
+ gpxpy 5463041.784135511 meters
88
+ gpxpy 5463041.784135511 meters
89
+ gpxpy: 37.803625 seconds (Average: 12.601208 seconds)
90
+ ```
91
+
92
+ #### xml_etree data extraction
93
+
94
+ ```
95
+ Running benchmark with 3 iterations...
96
+ xml_etree 5463043.740615641 meters
97
+ xml_etree 5463043.740615641 meters
98
+ xml_etree 5463043.740615641 meters
99
+ xml_etree: 2.333200 seconds (Average: 0.777733 seconds)
100
+ ```
101
+
102
+ Even with `gpxpy` using `etree` to parse the XML it is paster to parse it
103
+ directly with `etree` and use `gpxpy.geo` distance functions to compute the
104
+ distance of a GPX file. Unclear what the extra overhead is, possibly the cost
105
+ of extraction additional data. (Some minor difference in how the total distance
106
+ is computed in this example. Using different options for computing the distance.)
107
+
108
+ ### C++ benchmarks
109
+
110
+ Since XML parsing itself appear to have a significant impact on performance some
111
+ popular C++ XML libraries was tested:
112
+
113
+ #### tinyxml2
114
+ ```
115
+ Total Length: 5456930.710560566
116
+ Elapsed time: 0.4980144 seconds
117
+ ```
118
+
119
+ #### pugixml
120
+ ```
121
+ Total Length: 5456930.710560566
122
+ Elapsed time: 0.1890089 seconds
123
+ ```
124
+
125
+ ### C++ vs Python implementations
126
+
127
+
128
+ ```
129
+ Running 5 benchmarks with 3 iterations...
130
+
131
+ Running gpxpy ...
132
+ gpxpy: 50.182288 seconds (Average: 16.727429 seconds)
133
+
134
+ Running xml_etree ...
135
+ xml_etree: 8.269050 seconds (Average: 2.756350 seconds)
136
+
137
+ Running lxml ...
138
+ lxml: 8.479702 seconds (Average: 2.826567 seconds)
139
+
140
+ Running tinyxml (C++) ...
141
+ tinyxml (C++): 2.699880 seconds (Average: 0.899960 seconds)
142
+
143
+ Running pugixml (C++) ...
144
+ pugixml (C++): 0.381095 seconds (Average: 0.127032 seconds)
145
+ ```
146
+
147
+ For computing the length of a GPX file, `pugixml` in a Python C extension was ~140
148
+ times faster than using `gpxpy`.
@@ -0,0 +1,19 @@
1
+ fastgpx/__init__.py,sha256=Dhn14Vj7rvcXHlI3d5U7YUJ9kpiNqwyN5jjx21vhX6U,305
2
+ fastgpx/__init__.pyi,sha256=ZLJDcLlyBVoCyzfnNPJawul3-gaCEuk4cfBbE7gPlrg,496
3
+ fastgpx/fastgpx/__init__.pyi,sha256=bkG-4KO_GAFqG7JkpD282BCqpAZMDUBo9z2PX0l4B9o,3462
4
+ fastgpx/fastgpx/geo.pyi,sha256=ZVwdoWV2S2T_flLjubZP5w-8KBpSdCu9_XJiv_Nk1C8,396
5
+ fastgpx/fastgpx/polyline.pyi,sha256=-rA0DhdBy_iifRD4Z_6fxolprXZAcjCsf7RbeVnn4sI,1619
6
+ fastgpx/fastgpx.cp311-win_amd64.pyd,sha256=mBxEYe8M_ty7S1zeBuQkt2IISeW9VYWPWg-5hMD0vPE,1258496
7
+ fastgpx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ include/pugiconfig.hpp,sha256=jlfegptw715KDgZqHwl0-jcYoO5cerHNphaM9WDoJPg,2973
9
+ include/pugixml.hpp,sha256=geW_lTG67YQpTQy-OMqtttkNEPd8LXk-Lc6MX16vbCY,55813
10
+ lib/cmake/pugixml/pugixml-config-version.cmake,sha256=1JpMX7bIytKDIQj-0sYRyWi3OuqhYW2ejtHT2tguaK8,2824
11
+ lib/cmake/pugixml/pugixml-config.cmake,sha256=o26SUzcgGUIZx707opSfpPJulzF9qdZ5UhdxMPppIHE,1002
12
+ lib/cmake/pugixml/pugixml-targets-relwithdebinfo.cmake,sha256=Q4VX-_0WNB1rP4unAefSUak4UoJWdLzd4FxMMlmxHe4,902
13
+ lib/cmake/pugixml/pugixml-targets.cmake,sha256=Y_kk2s6vZuC3KKzBrBNUDVSHM-T_27jYwjl09j8amZU,4712
14
+ lib/pkgconfig/pugixml.pc,sha256=r8nNBHbEvOaiHzr2AIwtM0CrQw_0TwksBsAaHkPm71c,457
15
+ lib/pugixml.lib,sha256=6gVxeRqVvt4Jr08Nz_ka3Ke1yujjFolg_PhJP_dQ25o,1508704
16
+ fastgpx-0.1.0.dist-info/METADATA,sha256=GKQtUXerwQfnbGjZUZVtq0kprxv8d_-o8yykGO8Yzfo,4036
17
+ fastgpx-0.1.0.dist-info/WHEEL,sha256=xGZmaOXqwLlhmjR8ikRHIC1Wm-k3ULVrL-oi9GC-Mmc,106
18
+ fastgpx-0.1.0.dist-info/licenses/LICENSE.md,sha256=uiiKRcSY4AXOaDKTBOVF_1FW-8W6ATVoXYPm3UTOpu0,1111
19
+ fastgpx-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: scikit-build-core 0.11.1
3
+ Root-Is-Purelib: false
4
+ Tag: cp311-cp311-win_amd64
5
+
@@ -0,0 +1,22 @@
1
+
2
+ The MIT License (MIT)
3
+
4
+ Copyright (c) 2024-2025 Thomas Thomassen
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
include/pugiconfig.hpp ADDED
@@ -0,0 +1,77 @@
1
+ /**
2
+ * pugixml parser - version 1.14
3
+ * --------------------------------------------------------
4
+ * Copyright (C) 2006-2023, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
5
+ * Report bugs and download new versions at https://pugixml.org/
6
+ *
7
+ * This library is distributed under the MIT License. See notice at the end
8
+ * of this file.
9
+ *
10
+ * This work is based on the pugxml parser, which is:
11
+ * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
12
+ */
13
+
14
+ #ifndef HEADER_PUGICONFIG_HPP
15
+ #define HEADER_PUGICONFIG_HPP
16
+
17
+ // Uncomment this to enable wchar_t mode
18
+ // #define PUGIXML_WCHAR_MODE
19
+
20
+ // Uncomment this to enable compact mode
21
+ // #define PUGIXML_COMPACT
22
+
23
+ // Uncomment this to disable XPath
24
+ // #define PUGIXML_NO_XPATH
25
+
26
+ // Uncomment this to disable STL
27
+ // #define PUGIXML_NO_STL
28
+
29
+ // Uncomment this to disable exceptions
30
+ // #define PUGIXML_NO_EXCEPTIONS
31
+
32
+ // Set this to control attributes for public classes/functions, i.e.:
33
+ // #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
34
+ // #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
35
+ // #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
36
+ // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
37
+
38
+ // Tune these constants to adjust memory-related behavior
39
+ // #define PUGIXML_MEMORY_PAGE_SIZE 32768
40
+ // #define PUGIXML_MEMORY_OUTPUT_STACK 10240
41
+ // #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
42
+
43
+ // Tune this constant to adjust max nesting for XPath queries
44
+ // #define PUGIXML_XPATH_DEPTH_LIMIT 1024
45
+
46
+ // Uncomment this to switch to header-only version
47
+ // #define PUGIXML_HEADER_ONLY
48
+
49
+ // Uncomment this to enable long long support
50
+ // #define PUGIXML_HAS_LONG_LONG
51
+
52
+ #endif
53
+
54
+ /**
55
+ * Copyright (c) 2006-2023 Arseny Kapoulkine
56
+ *
57
+ * Permission is hereby granted, free of charge, to any person
58
+ * obtaining a copy of this software and associated documentation
59
+ * files (the "Software"), to deal in the Software without
60
+ * restriction, including without limitation the rights to use,
61
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
62
+ * copies of the Software, and to permit persons to whom the
63
+ * Software is furnished to do so, subject to the following
64
+ * conditions:
65
+ *
66
+ * The above copyright notice and this permission notice shall be
67
+ * included in all copies or substantial portions of the Software.
68
+ *
69
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
70
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
71
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
72
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
73
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
74
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
75
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
76
+ * OTHER DEALINGS IN THE SOFTWARE.
77
+ */