Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project adheres to Calendar Versioning.
The first number of the version is the year. The second number is incremented with each release, starting at 1 for each year. The third number is for emergencies when we need to start branches for older releases.
Unreleased¶
Added¶
New
operationsmodule that exposes the editing and merging operations behind thegpx editandgpx mergeCLI commands as a public, reusable API:crop(): Crop a GPX to a geographic bounding boxtrim(): Trim a GPX to a date/time rangereverse(): Reverse the routes and/or tracks of a GPXstrip_metadata(): Strip metadata (fields) from a GPXreduce_precision(): Reduce the precision of the coordinates and/or elevations of a GPXfilter_points(): Filter the points of a GPX with an arbitrary predicatemerge(): Merge multiple GPX instances into onesplit(): Split track segments at time and/or distance gapssimplify(): Simplify the tracks and routes of a GPX with the Ramer-Douglas-Peucker algorithmsmooth(): Smooth the coordinates and/or elevations of the tracks and routes of a GPX with a moving averageshift_time(): Shift all point timestamps of a GPX by a time deltastrip_extensions(): Strip all extensions from a GPXAll operations are pure (they return a new
GPXinstance and never mutate the input) and are importable directly from the top-level package (e.g.from gpx import crop, merge).
New
gpx editCLI options exposing the new operations:--split-time-gap SECONDSand--split-distance-gap METERS: Split track segments at gaps--simplify TOLERANCE: Simplify tracks and routes (tolerance in metres)--smooth WINDOW: Smooth track and route coordinates and elevations with a moving average--shift-time SECONDS: Shift all point timestamps (may be negative)--strip-extensions: Strip all extensions
New file conversion functions in the
iomodule, exposing the operation behind thegpx convertCLI command as a public, reusable API:convert_file(): Convert a file between the GPX, GeoJSON and KML file formatsdetect_format(): Detect the file format from a file path’s extensionBoth are importable directly from the top-level package (e.g.
from gpx import convert_file).
New
validationmodule that validates GPX data against the GPX 1.1 schema (gpx.xsd) without any extra dependencies:validate(): Validate a file path, a string of GPX content, or aGPXinstance and return aValidationResult.ValidationResult: Holds all issues, withis_valid,errorsandwarningsproperties.ValidationIssue: A single issue with aseverity,message,path(e.g.gpx > trk[0] > trkseg[2] > trkpt[14]) and sourceline(when available).Severity: Enum ofERRORandWARNING.InvalidGPXError: Raised by strict parsing; carries the fullValidationResult.Detects, among others: wrong root element / namespace (with a GPX 1.0 hint), missing required attributes, unknown elements (with “did you mean …?” suggestions), duplicate single-occurrence elements, out-of-order children,
<extensions>children that are not in a foreign namespace (e.g. unprefixed elements that inherit the default GPX namespace), and invalid values (latitude/longitude/degrees ranges,fix,dgpsid,sat, copyrightyear,time).All names are importable directly from the top-level package (e.g.
from gpx import validate).
New
strictkeyword argument onread_gpx()andfrom_string(). Whenstrict=True, the input is validated against the GPX 1.1 schema first and anInvalidGPXErroris raised if any errors are found. The default (strict=False) keeps the existing lenient behavior.New
gpx validateCLI options:--strict: Treat warnings as failures (non-zero exit code).--json: Output a machine-readable validation report.
New
--strictoption on thegpx info,gpx edit,gpx mergeandgpx convertCLI commands. When given, each input is validated against the GPX 1.1 schema first: warnings are printed to stderr and the command aborts (non-zero exit code) if any schema errors are found. Forgpx convert, validation only applies to GPX input. The default keeps the existing lenient behavior.
Changed¶
The CLI (
gpx edit,gpx mergeandgpx convert) now uses the newoperationsmodule andioconversion functions internally (behavior is unchanged).The
gpx validateCLI command is now a real GPX 1.1 schema validator. It reports all errors and warnings (with source line numbers) instead of only checking whether the file can be parsed, and exits non-zero when errors are found (or, with--strict, when warnings are found).
2026.3.0 - 2026-05-17¶
This third release in the year 2026 adds a new GeoGPXModel base class for GPX models that carry geometric data.
Added¶
New
GeoGPXModelbase class for GPX models that carry geometric data (Waypoint,Route,TrackSegment,Track,Bounds,GPX). Enablesisinstance()checks and type-hinted handling of geometric models, and enforces that subclasses implement__geo_interface__.
2026.2.0 - 2026-04-27¶
This second major release in the year 2026 adds support for GPX extensions, and includes a range of bug fixes and robustness improvements.
Added¶
GPX Extensions support: Added
Extensionsclass for handling GPX extension elements from any XML namespace (e.g., Garmin’sTrackPointExtension). Extensions are now parsed, preserved, and serialized during round-trip processing, enabling lossless handling of vendor-specific data like heart rate, cadence, temperature, etc.New
extensionsfield on all models that support extensions per the GPX 1.1 spec:GPX,Metadata,Waypoint,Track,TrackSegment, andRoute.
Changed¶
Tracknow inherits fromPointsMixinand reuses its bounds and elevation aggregations (bounds,_points_with_ele,_eles,avg_elevation,min_elevation,max_elevation,diff_elevation,avg_speed,avg_moving_speed), eliminating duplication betweenTrackand the segment/route mixin. Per-segment semantics are preserved for distance, duration, speed extremes, ascent/descent and the elevation profile by overriding only those properties.intandboolfields in__geo_interface__properties (e.g.Waypoint.sat,Track.number,Route.number) now keep their JSON-native types.
Removed¶
Removed obsolete
remove_encoding_from_stringfunction.
Fixed¶
EWKB format parsing now correctly handles Z coordinates by checking the EWKB flag before the ISO WKB flag.
gpx editno longer drops custom XML namespace prefixes (e.g.gpxtpx,gpxx) from the source file. All edit transformations (crop, trim, reverse, precision, strip metadata) now propagatensmapso round-trips preserve the original prefixes.gpx edit --min-lat 0(and the other crop bounds) is no longer silently ignored.Track.elevation_profileno longer skips the first elevation-bearing point of segments after the first, and no longer raisesIndexErrorfor tracks with no segments or no points with elevation.PointsMixin.elevation_profile(used byRouteandTrackSegment) similarly returns[]for empty inputs instead of crashing.Waypoint.speed_tono longer raisesZeroDivisionErrorwhen two waypoints share a timestamp (or either lacks one); it returns0.0instead. This also fixes downstream crashes inPointsMixin._speeds,max_speed,min_speed,moving_duration, andspeed_profilefor tracks containing consecutive points with identical timestamps.Waypoint.slope_tosimilarly returnsDecimal(0)instead of raisingZeroDivisionErrorwhen two waypoints share coordinates.
2026.1.0 - 2026-01-07¶
This first major release in the year 2026 adds two new features to the package: file format conversion (i.e. from GPX to GeoJSON, KML, WKT and/or WKB and vice versa) and a command-line interface (CLI).
Added¶
New
climodule with command-line interface (CLI) for common GPX operations:gpx validate: Validate a GPX filegpx info: Show information and statistics about a GPX filegpx edit: Edit a GPX file with various transformations:Crop to a geographic bounding box (
--min-lat,--min-lon,--max-lat,--max-lon)Trim to a date/time range (
--start,--end)Reverse routes and/or tracks (
--reverse,--reverse-routes,--reverse-tracks)Strip metadata fields (
--strip-name,--strip-desc,--strip-author,--strip-copyright,--strip-time,--strip-keywords,--strip-links,--strip-all-metadata)Reduce coordinate precision (
--precision,--elevation-precision)
gpx merge: Merge multiple GPX files into onegpx convert: Convert between GPX, GeoJSON, and KML formats
New CLI reference documentation page with auto-generated help output using
cogNew
iomodule withread_*()functions for reading file formats:read_gpx(): Read GPX filesread_geojson(): Read GeoJSON filesread_kml(): Read KML files
New
convertmodule withfrom_*()functions for converting from data formats:from_string(): Convert from a GPX stringfrom_geo_interface(): Convert from objects that implement the__geo_interface__protocol (e.g., Shapely)from_wkb(): Convert from Well-Known Binary bytesfrom_wkt(): Convert from Well-Known Text strings
New
write_*()methods on theGPXclass for writing to file formats:write_gpx(): Write to GPX file (renamed fromto_file())write_geojson(): Write to GeoJSON filewrite_kml(): Write to KML file (Google Earth format)
New
to_*()methods on theGPXclass for converting to data formats:to_wkt(): Convert to Well-Known Text (OGC standard)to_wkb(): Convert to Well-Known Binary (OGC standard)
Changed¶
Renamed
GPX.to_file()toGPX.write_gpx()for consistency with other write methods.Replaced built-in
tempfilemodule usage with pytest’stmp_pathandtmp_path_factoryfixtures in the test suite for better test isolation and automatic cleanup.
Removed¶
All aliases and proxies.
GPX.from_file()method in favor ofio.read_gpx().GPX.from_string()method in favor ofconvert.from_string().
2025.1.0 - 2025-11-29¶
This is a major release with a lot of breaking changes, primarily due to a complete rewrite of the architecture, and a general modernization of the package. Besides the change in architecture, this release adds comprehensive unit tests, enforces strict linting rules, and drops support folder older versions of Python. Finally, this release implements the __geo_interface__ protocol for all GPX elements that contain geopgraphic information, thus adding support for converting to GeoJSON.
Migration notes for users upgrading from 0.2.x:
Ensure you are using Python 3.11 or higher
Update constructor calls to use keyword arguments for optional parameters
Update field names to use GPX-standard names (e.g.,
trkseginstead oftrksegs)Remove
validate=Truefromfrom_file()andfrom_string()callsUpdate error handling to catch standard Python exceptions instead of
gpx.errors.ParseError
Example:
# Before (0.2.x)
from gpx import GPX, Waypoint
gpx = GPX.from_file("path/to/track.gpx", validate=True)
waypoint = Waypoint()
waypoint.lat = Decimal("52.0")
waypoint.lon = Decimal("4.0")
waypoint.name = "Amsterdam"
gpx.waypoints.append(waypoint)
# After (2025.1.0)
from gpx import GPX, Waypoint
from decimal import Decimal
gpx = GPX.from_file("path/to/track.gpx")
waypoint = Waypoint(Decimal("52.0"), Decimal("4.0"), name="Amsterdam")
gpx.wpt.append(waypoint)
Added¶
CLAUDE.mdfor easier interoperability with Claude Code.Comprehensive unit tests.
Smoke test.
Testing workflow via GitHub Actions.
Support for Python 3.12, 3.13 and 3.14.
More usage examples in
README.md.__geo_interface__protocol for all GPX elements that contain geographic information.
Changed¶
Upgraded the
pre-commithooks.Enabled ALL rules for the
rufflinter by default.Use the
uvbuild backend instead offlit.Updated the installation instructions to make use of
uvinstead ofpip.Switched the versioning scheme from semantic versioning to Calendar Versioning.
Refactored the GPX element classes into
dataclass-based models.Replaced
lxmlwith the built-inElementTreemodule.Optional dependencies to dependency groups.
Renamed
PyGPXtogpx(purely aesthetically, no changes in installation or usage required).
Removed¶
Support for Python 3.7, 3.8, 3.9 and 3.10.
The errors module.
Fixed¶
Erroneous examples in the usage examples in
README.md.
0.2.1 (2023-04-09)¶
Fixed¶
Serialization of route and track numbers. #10
Mutable default values. #11
0.2.0 (2023-04-06)¶
With this release, PyGPX is now fully [1] compatible with the GPX 1.1 specification.
Changes¶
Added the following new modules and classes:
gpx.element.Elementgpx.mixins.AttributesMutableMappingMixingpx.mixins.PointsSequenceMixingpx.mixins.PointsMutableSequenceMixin
All element classes now inherit from the new
gpx.element.Elementbase class.All element classes now make use of the new element / type classes (e.g.
gpx.types.Latitude), according to the GPX 1.1 specification.Added the
gpx.errors.ParseErrorexception for when attempting to parse an XML element that does not exist.All metadata attributes have been moved to the new
gpx.metadata.Metadataclass, but are still accessible via thegpx.gpx.GPXclass via aliases for backwards compatibility and convenience.Changed all
durationattributes todatetime.timedeltaobjects (instead offloats).
0.1.1 (2023-03-31)¶
This release introduces a completely overhauled codebase. For this, I used my cookiecutter-python-package Python package template. As such, this release comes with much higher code quality, documentation and automation.
The API itself has not changed (and as such, there is no minor version bump).
Changes¶
Completely refactored codebase, with:
Moved source code from
./gpxto./src/gpxFully typed and documented
Added documentation via Read the Docs
Updated CI/CD via GitHub Actions
Added pre-commit hooks w/ CI-integration
0.1.0 (2021-06-08)¶
Changes¶
Initial release of PyGPX