Repository: stravalib/stravalib
Pull request #509 (2024-05-18 08:41:02)

Summary segments
Adds type hierarchy and associated updated for Segment/SummarySegment types, See #499,  #506.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/stravalib/stravalib/pull/509?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=stravalib) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Please [upload](https://docs.codecov.com/docs/codecov-uploader) report for BASE (`pydantic-v2@26c2e9f`). [Learn more](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=stravalib#section-missing-base-commit) about missing BASE report.


<details><summary>Additional details and impacted files</summary>


```diff
@@              Coverage Diff               @@
##             pydantic-v2     #509   +/-   ##
==============================================
  Coverage               ?   89.26%           
==============================================
  Files                  ?       10           
  Lines                  ?     1808           
  Branches               ?      170           
==============================================
  Hits                   ?     1614           
  Misses                 ?      154           
  Partials               ?       40           
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/stravalib/stravalib/pull/509?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=stravalib).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=stravalib).


Patch:
diff --git a/src/stravalib/client.py b/src/stravalib/client.py
index 72dbd3c..003e702 100644
--- a/src/stravalib/client.py
+++ b/src/stravalib/client.py
@@ -1289,7 +1289,7 @@ class Client:
 
     def get_starred_segments(
         self, limit: int | None = None
-    ) -> BatchedResultsIterator[model.Segment]:
+    ) -> BatchedResultsIterator[model.SummarySegment]:
         """Returns a summary representation of the segments starred by the
          authenticated user. Pagination is supported.
 
@@ -1303,7 +1303,7 @@ class Client:
         Returns
         -------
         class:`BatchedResultsIterator`
-            An iterator of :class:`stravalib.model.Segment` starred by authenticated user.
+            An iterator of :class:`stravalib.model.SummarySegment` starred by authenticated user.
 
         """
 
@@ -1316,7 +1316,7 @@ class Client:
         )
 
         return BatchedResultsIterator(
-            entity=model.Segment,
+            entity=model.SummarySegment,
             bind_client=self,
             result_fetcher=result_fetcher,
             limit=limit,
diff --git a/src/stravalib/model.py b/src/stravalib/model.py
index 9891b79..e9c8cff 100644
--- a/src/stravalib/model.py
+++ b/src/stravalib/model.py
@@ -39,7 +39,6 @@ from stravalib.strava_model import (
     Comment,
     DetailedClub,
     DetailedGear,
-    DetailedSegment,
     DetailedSegmentEffort,
     ExplorerSegment,
     Lap,
@@ -743,22 +742,27 @@ class AthletePrEffort(
         return self.pr_elapsed_time
 
 
-class Segment(
-    DetailedSegment,
-    BoundClientEntity,
-):
-    """
-    Represents a single Strava segment.
-    """
-
+class SummarySegment(strava_model.SummarySegment, BoundClientEntity):
     # Field overrides from superclass for type extensions:
     start_latlng: Optional[LatLon] = None
     end_latlng: Optional[LatLon] = None
-    map: Optional[Map] = None
     athlete_segment_stats: Optional[AthleteSegmentStats] = None
     athlete_pr_effort: Optional[AthletePrEffort] = None
     activity_type: Optional[RelaxedActivityType] = None  # type: ignore[assignment]
 
+    _latlng_check = field_validator(
+        "start_latlng", "end_latlng", mode="before"
+    )(check_valid_location)
+
+
+class Segment(SummarySegment, strava_model.DetailedSegment):
+    """
+    Represents a single Strava segment.
+    """
+
+    # Field overrides from superclass for type extensions:
+    map: Optional[Map] = None
+
     # Undocumented attributes:
     start_latitude: Optional[float] = None
     end_latitude: Optional[float] = None
@@ -769,10 +773,6 @@ class Segment(
     starred_date: Optional[datetime] = None
     elevation_profile: Optional[str] = None
 
-    _latlng_check = field_validator(
-        "start_latlng", "end_latlng", mode="before"
-    )(check_valid_location)
-
 
 class SegmentEffortAchievement(BaseModel):
     """
@@ -810,7 +810,7 @@ class BaseEffort(
     """
 
     # Field overrides from superclass for type extensions:
-    segment: Optional[Segment] = None
+    segment: Optional[SummarySegment] = None
     activity: Optional[Activity] = None
     athlete: Optional[Athlete] = None
 
@@ -995,7 +995,7 @@ class Route(
     # Superclass field overrides for using extended types
     athlete: Optional[SummaryAthlete] = None
     map: Optional[Map] = None
-    segments: Optional[list[Segment]]  # type: ignore[assignment]
+    segments: Optional[list[SummarySegment]]  # type: ignore[assignment]
 
 
 class Subscription(BaseModel):


Test patch:
diff --git a/src/stravalib/tests/integration/test_client.py b/src/stravalib/tests/integration/test_client.py
index 6d8d1d8..c2ee3b0 100644
--- a/src/stravalib/tests/integration/test_client.py
+++ b/src/stravalib/tests/integration/test_client.py
@@ -9,7 +9,7 @@ from responses import matchers
 
 from stravalib.client import ActivityUploader
 from stravalib.exc import AccessUnauthorized, ActivityPhotoUploadFailed
-from stravalib.model import Athlete, SummaryAthlete
+from stravalib.model import Athlete, SummaryAthlete, SummarySegment
 from stravalib.strava_model import SummaryActivity
 from stravalib.tests import RESOURCES_DIR
 from stravalib.unithelper import miles
@@ -719,10 +719,11 @@ def test_get_starred_segments(
         n_results=n_raw_results,
     )
     kwargs = {"limit": limit} if limit is not None else {}
-    activity_list = list(client.get_starred_segments(**kwargs))
-    assert len(activity_list) == expected_n_segments
+    segment_list = list(client.get_starred_segments(**kwargs))
+    assert len(segment_list) == expected_n_segments
     if expected_n_segments > 0:
-        assert activity_list[0].name == "test_segment"
+        assert isinstance(segment_list[0], SummarySegment)
+        assert segment_list[0].name == "test_segment"
 
 
 def test_get_club(mock_strava_api, client):