fleetpull 0.1.0__tar.gz → 0.1.2__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.
Files changed (263) hide show
  1. {fleetpull-0.1.0 → fleetpull-0.1.2}/PKG-INFO +1 -1
  2. {fleetpull-0.1.0 → fleetpull-0.1.2}/pyproject.toml +1 -1
  3. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/__init__.py +1 -1
  4. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/trips.py +10 -4
  5. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/idle_event.py +20 -8
  6. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/trip.py +41 -19
  7. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/decoders/__init__.py +2 -0
  8. fleetpull-0.1.2/src/fleetpull/network/decoders/samsara_trips.py +105 -0
  9. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull.egg-info/PKG-INFO +1 -1
  10. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull.egg-info/SOURCES.txt +1 -0
  11. {fleetpull-0.1.0 → fleetpull-0.1.2}/LICENSE +0 -0
  12. {fleetpull-0.1.0 → fleetpull-0.1.2}/README.md +0 -0
  13. {fleetpull-0.1.0 → fleetpull-0.1.2}/setup.cfg +0 -0
  14. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/api/__init__.py +0 -0
  15. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/api/auth_ingress.py +0 -0
  16. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/api/catalog.py +0 -0
  17. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/api/fetch.py +0 -0
  18. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/api/identity.py +0 -0
  19. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/api/sync.py +0 -0
  20. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/cli.py +0 -0
  21. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/__init__.py +0 -0
  22. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/base.py +0 -0
  23. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/example.py +0 -0
  24. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/geotab.py +0 -0
  25. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/http.py +0 -0
  26. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/loading.py +0 -0
  27. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/logger.py +0 -0
  28. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/providers.py +0 -0
  29. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/rate_limit.py +0 -0
  30. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/resolution.py +0 -0
  31. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/retry.py +0 -0
  32. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/root.py +0 -0
  33. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/config/sections.py +0 -0
  34. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/__init__.py +0 -0
  35. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/__init__.py +0 -0
  36. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/_requests.py +0 -0
  37. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/annotation_logs.py +0 -0
  38. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/audits.py +0 -0
  39. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/devices.py +0 -0
  40. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/driver_changes.py +0 -0
  41. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/duty_status_logs.py +0 -0
  42. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/dvir_logs.py +0 -0
  43. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/exception_events.py +0 -0
  44. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/fault_data.py +0 -0
  45. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/fill_ups.py +0 -0
  46. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/fuel_and_energy_used.py +0 -0
  47. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/fuel_tax_details.py +0 -0
  48. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/log_records.py +0 -0
  49. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/media_files.py +0 -0
  50. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/shipment_logs.py +0 -0
  51. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/status_data.py +0 -0
  52. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/text_messages.py +0 -0
  53. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/trips.py +0 -0
  54. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/geotab/users.py +0 -0
  55. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/__init__.py +0 -0
  56. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/_spec_builders.py +0 -0
  57. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/driver_idle_rollups.py +0 -0
  58. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/driving_periods.py +0 -0
  59. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/groups.py +0 -0
  60. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/idle_events.py +0 -0
  61. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/users.py +0 -0
  62. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/vehicle_locations.py +0 -0
  63. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/vehicle_utilizations.py +0 -0
  64. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/motive/vehicles.py +0 -0
  65. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/registry.py +0 -0
  66. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/__init__.py +0 -0
  67. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/_spec_builders.py +0 -0
  68. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/addresses.py +0 -0
  69. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/asset_locations.py +0 -0
  70. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/driver_fuel_energy_reports.py +0 -0
  71. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/driver_vehicle_assignments.py +0 -0
  72. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/drivers.py +0 -0
  73. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/engine_states.py +0 -0
  74. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/gps_readings.py +0 -0
  75. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/idling_events.py +0 -0
  76. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/odometer_readings.py +0 -0
  77. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/vehicle_fuel_energy_reports.py +0 -0
  78. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/samsara/vehicles.py +0 -0
  79. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/shared/__init__.py +0 -0
  80. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/shared/base.py +0 -0
  81. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/shared/request_shape.py +0 -0
  82. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/shared/resume.py +0 -0
  83. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/shared/spec_builders.py +0 -0
  84. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/shared/sync_mode.py +0 -0
  85. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/endpoints/shared/url_paths.py +0 -0
  86. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/exceptions.py +0 -0
  87. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/incremental/__init__.py +0 -0
  88. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/incremental/cursor.py +0 -0
  89. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/incremental/resolution.py +0 -0
  90. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/incremental/seed.py +0 -0
  91. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/incremental/window.py +0 -0
  92. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/logger/__init__.py +0 -0
  93. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/logger/setup.py +0 -0
  94. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/model_contract/__init__.py +0 -0
  95. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/model_contract/coercions.py +0 -0
  96. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/model_contract/response.py +0 -0
  97. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/__init__.py +0 -0
  98. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/__init__.py +0 -0
  99. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/annotation_log.py +0 -0
  100. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/audit.py +0 -0
  101. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/device.py +0 -0
  102. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/driver_change.py +0 -0
  103. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/duty_status_log.py +0 -0
  104. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/dvir_log.py +0 -0
  105. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/exception_event.py +0 -0
  106. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/fault_data.py +0 -0
  107. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/fill_up.py +0 -0
  108. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/fuel_and_energy_used.py +0 -0
  109. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/fuel_tax_detail.py +0 -0
  110. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/log_record.py +0 -0
  111. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/media_file.py +0 -0
  112. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/shared.py +0 -0
  113. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/shipment_log.py +0 -0
  114. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/status_data.py +0 -0
  115. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/text_message.py +0 -0
  116. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/trip.py +0 -0
  117. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/geotab/user.py +0 -0
  118. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/__init__.py +0 -0
  119. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/driver_idle_rollup.py +0 -0
  120. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/driving_period.py +0 -0
  121. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/group.py +0 -0
  122. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/shared.py +0 -0
  123. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/user.py +0 -0
  124. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/vehicle.py +0 -0
  125. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/vehicle_location.py +0 -0
  126. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/motive/vehicle_utilization.py +0 -0
  127. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/__init__.py +0 -0
  128. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/address.py +0 -0
  129. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/asset_location.py +0 -0
  130. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/driver.py +0 -0
  131. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/driver_fuel_energy_report.py +0 -0
  132. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/driver_vehicle_assignment.py +0 -0
  133. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/engine_state.py +0 -0
  134. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/gps_reading.py +0 -0
  135. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/idling_event.py +0 -0
  136. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/odometer_reading.py +0 -0
  137. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/vehicle.py +0 -0
  138. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/models/samsara/vehicle_fuel_energy_report.py +0 -0
  139. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/__init__.py +0 -0
  140. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/auth/__init__.py +0 -0
  141. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/auth/authenticate.py +0 -0
  142. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/auth/manager.py +0 -0
  143. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/auth/models.py +0 -0
  144. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/auth/strategies.py +0 -0
  145. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/classifiers/__init__.py +0 -0
  146. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/classifiers/geotab.py +0 -0
  147. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/classifiers/motive.py +0 -0
  148. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/classifiers/samsara.py +0 -0
  149. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/client/__init__.py +0 -0
  150. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/client/page.py +0 -0
  151. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/client/profile.py +0 -0
  152. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/client/registry.py +0 -0
  153. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/client/registry_base.py +0 -0
  154. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/client/runtime.py +0 -0
  155. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/client/transport.py +0 -0
  156. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/contract/__init__.py +0 -0
  157. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/contract/auth.py +0 -0
  158. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/contract/classifier.py +0 -0
  159. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/contract/envelope_fetcher.py +0 -0
  160. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/contract/envelopes.py +0 -0
  161. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/contract/outcome.py +0 -0
  162. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/contract/page_decoder.py +0 -0
  163. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/contract/request.py +0 -0
  164. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/decoders/_window_stamp.py +0 -0
  165. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/decoders/geotab.py +0 -0
  166. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/decoders/motive.py +0 -0
  167. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/decoders/motive_reports.py +0 -0
  168. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/decoders/samsara.py +0 -0
  169. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/decoders/samsara_reports.py +0 -0
  170. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/decoders/single_page.py +0 -0
  171. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/limits/__init__.py +0 -0
  172. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/limits/bucket_math.py +0 -0
  173. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/limits/limiter.py +0 -0
  174. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/limits/registry.py +0 -0
  175. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/posture/__init__.py +0 -0
  176. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/posture/client_options.py +0 -0
  177. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/retry/__init__.py +0 -0
  178. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/retry/decision.py +0 -0
  179. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/tls/__init__.py +0 -0
  180. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/network/tls/truststore_context.py +0 -0
  181. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/__init__.py +0 -0
  182. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/backfill.py +0 -0
  183. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/batch.py +0 -0
  184. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/bisection.py +0 -0
  185. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/drivers.py +0 -0
  186. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/entry.py +0 -0
  187. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/executors.py +0 -0
  188. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/fanout.py +0 -0
  189. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/feed_drive.py +0 -0
  190. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/metadata_projection.py +0 -0
  191. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/outcome.py +0 -0
  192. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/recording.py +0 -0
  193. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/resume.py +0 -0
  194. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/roster_harvest.py +0 -0
  195. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/roster_refresh.py +0 -0
  196. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/runner.py +0 -0
  197. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/shape_resolution.py +0 -0
  198. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/spine.py +0 -0
  199. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/streaming.py +0 -0
  200. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/unit_loop.py +0 -0
  201. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/orchestrator/watermark_drive.py +0 -0
  202. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/paths/__init__.py +0 -0
  203. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/paths/datasets.py +0 -0
  204. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/paths/partitions.py +0 -0
  205. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/paths/resolution.py +0 -0
  206. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/polars_typing/__init__.py +0 -0
  207. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/py.typed +0 -0
  208. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/__init__.py +0 -0
  209. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/convert.py +0 -0
  210. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/dataframe.py +0 -0
  211. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/event_time.py +0 -0
  212. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/fields.py +0 -0
  213. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/flatten.py +0 -0
  214. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/roster_members.py +0 -0
  215. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/schema.py +0 -0
  216. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/records/validation.py +0 -0
  217. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/resources/__init__.py +0 -0
  218. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/resources/config.example.yaml +0 -0
  219. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/roster/__init__.py +0 -0
  220. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/roster/definition.py +0 -0
  221. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/roster/key.py +0 -0
  222. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/roster/registry.py +0 -0
  223. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/state/__init__.py +0 -0
  224. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/state/cursors.py +0 -0
  225. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/state/database.py +0 -0
  226. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/state/migrations.py +0 -0
  227. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/state/reconcile.py +0 -0
  228. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/state/rosters.py +0 -0
  229. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/state/run_ledger.py +0 -0
  230. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/state/work_units.py +0 -0
  231. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/__init__.py +0 -0
  232. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/append.py +0 -0
  233. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/atomic.py +0 -0
  234. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/files.py +0 -0
  235. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/frames.py +0 -0
  236. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/metadata.py +0 -0
  237. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/partitioned.py +0 -0
  238. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/pruning.py +0 -0
  239. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/read.py +0 -0
  240. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/result.py +0 -0
  241. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/single_file.py +0 -0
  242. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/splitting.py +0 -0
  243. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/staging.py +0 -0
  244. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/storage/writers.py +0 -0
  245. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/timing/__init__.py +0 -0
  246. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/timing/canon.py +0 -0
  247. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/timing/clock.py +0 -0
  248. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/timing/codec.py +0 -0
  249. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/timing/sleeper.py +0 -0
  250. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/vocabulary/__init__.py +0 -0
  251. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/vocabulary/json_types.py +0 -0
  252. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/vocabulary/provider.py +0 -0
  253. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/vocabulary/quota_scope.py +0 -0
  254. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull/vocabulary/response_category.py +0 -0
  255. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull.egg-info/dependency_links.txt +0 -0
  256. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull.egg-info/entry_points.txt +0 -0
  257. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull.egg-info/requires.txt +0 -0
  258. {fleetpull-0.1.0 → fleetpull-0.1.2}/src/fleetpull.egg-info/top_level.txt +0 -0
  259. {fleetpull-0.1.0 → fleetpull-0.1.2}/tests/test_cli.py +0 -0
  260. {fleetpull-0.1.0 → fleetpull-0.1.2}/tests/test_exceptions.py +0 -0
  261. {fleetpull-0.1.0 → fleetpull-0.1.2}/tests/test_import_discipline.py +0 -0
  262. {fleetpull-0.1.0 → fleetpull-0.1.2}/tests/test_temporal_discipline.py +0 -0
  263. {fleetpull-0.1.0 → fleetpull-0.1.2}/tests/test_typing_discipline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fleetpull
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Pull fleet telematics data from provider APIs (Motive, Samsara, GeoTab) into typed polars DataFrames and parquet: retrieval, dtype coercion, and light structural normalization — no assumed end use.
5
5
  Author-email: Andrew Jordan <andrewjordan3@gmail.com>
6
6
  Maintainer-email: Andrew Jordan <andrewjordan3@gmail.com>
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
  ###############################################################################
10
10
  [project]
11
11
  name = "fleetpull"
12
- version = "0.1.0"
12
+ version = "0.1.2"
13
13
  description = "Pull fleet telematics data from provider APIs (Motive, Samsara, GeoTab) into typed polars DataFrames and parquet: retrieval, dtype coercion, and light structural normalization — no assumed end use."
14
14
  readme = "README.md"
15
15
  authors = [{ name = "Andrew Jordan", email = "andrewjordan3@gmail.com" }]
@@ -21,7 +21,7 @@ from fleetpull.exceptions import (
21
21
  SyncFailuresError,
22
22
  )
23
23
 
24
- __version__: str = '0.1.0'
24
+ __version__: str = '0.1.2'
25
25
 
26
26
  __all__: list[str] = [
27
27
  'AuthenticationError',
@@ -14,8 +14,12 @@ member merges as a QUERY parameter -- the drivers-leaf precedent, not
14
14
  the Motive path-template one.
15
15
 
16
16
  The envelope is ``{"trips": [...]}`` with no pagination of any kind:
17
- one response per (vehicle, window), so the shared ``SinglePageDecoder``
18
- fits (the GeoTab exception_events pairing precedent). Retrieval is
17
+ one response per (vehicle, window). The wire record does NOT echo the
18
+ requested ``vehicleId``, so the binding pairs it with
19
+ ``SamsaraTripsPageDecoder``, which stamps every trip with the fan-out
20
+ member's ``vehicleId`` copied off the sent spec (the report family's
21
+ sent-spec stamp applied to a fan-out member) -- without it the stored
22
+ row carries no vehicle identity. Retrieval is
19
23
  OVERLAP-anchored, re-verified per-type 2026-07-20 (a 60-second window
20
24
  strictly inside a trip's span returned that trip; start- and
21
25
  end-anchoring falsified -- DESIGN §4's historical record for this exact
@@ -50,7 +54,7 @@ from fleetpull.endpoints.shared import (
50
54
  )
51
55
  from fleetpull.models.samsara import Trip
52
56
  from fleetpull.network.contract import HttpMethod, RequestSpec
53
- from fleetpull.network.decoders import SinglePageDecoder
57
+ from fleetpull.network.decoders import SamsaraTripsPageDecoder
54
58
  from fleetpull.roster import RosterKey
55
59
  from fleetpull.timing import require_utc
56
60
  from fleetpull.vocabulary import Provider, QuotaScope
@@ -201,7 +205,9 @@ def build_endpoint(config: SamsaraConfig) -> EndpointDefinition[Trip]:
201
205
  spec_builder=SamsaraTripsSpecBuilder(
202
206
  base_url=config.base_url, path=_TRIPS_PATH
203
207
  ),
204
- page_decoder=SinglePageDecoder(records_key=_RECORDS_KEY),
208
+ page_decoder=SamsaraTripsPageDecoder(
209
+ records_key=_RECORDS_KEY, member_key=_VEHICLE_ID_PARAM
210
+ ),
205
211
  response_model=Trip,
206
212
  quota_scope=QuotaScope.SAMSARA,
207
213
  storage_kind=StorageKind.DATE_PARTITIONED,
@@ -9,6 +9,15 @@ the provider's reverse-geocode metadata; when ``rg_match`` is false,
9
9
  ``location`` carries a distance-direction prefix (``"2.6 mi NW of …"``)
10
10
  instead of a bare place name — both formats mirror verbatim.
11
11
 
12
+ The reverse-geocode PLACE fields (``city``/``state``/``rg_brg``/``rg_km``)
13
+ are OPTIONAL: the 2026-07-15 census saw them on every record (including
14
+ the ``rg_match: false`` ones, which still carry a nearby place), but a
15
+ larger live pull (2026-07-22) returned all four null when the geocoder
16
+ matched NO nearby place at all — the census-scope lesson (a bounded
17
+ census proves a shape present, never absent). So a no-place record
18
+ validates and mirrors the nulls rather than failing the sync loudly (the
19
+ ``veh_fuel`` null-counter precedent).
20
+
12
21
  The endpoint's date window is interpreted on company-local day boundaries
13
22
  and matched by overlap (DESIGN §8, captured 2026-07-15) — the reason its
14
23
  endpoint leaf pads the wire window; nothing about that reaches this
@@ -43,11 +52,14 @@ class IdleEvent(ResponseModel):
43
52
  when the vehicle reports no fuel counters.
44
53
  lat: Event latitude.
45
54
  lon: Event longitude.
46
- city: Reverse-geocoded place name.
47
- state: Reverse-geocoded state / province code.
48
- rg_brg: Reverse-geocode bearing from the matched place, degrees.
55
+ city: Reverse-geocoded place name; null when the geocoder matched
56
+ no nearby place (live-observed 2026-07-22).
57
+ state: Reverse-geocoded state / province code; null when no place
58
+ matched.
59
+ rg_brg: Reverse-geocode bearing from the matched place, degrees;
60
+ null when no place matched.
49
61
  rg_km: Reverse-geocode distance from the matched place,
50
- kilometers.
62
+ kilometers; null when no place matched.
51
63
  rg_match: Whether the reverse geocoder matched a place directly.
52
64
  end_type: Free-form interval-end reason (``"engine_stop"`` /
53
65
  ``"vehicle_moving"`` observed), mirrored, never interpreted.
@@ -65,10 +77,10 @@ class IdleEvent(ResponseModel):
65
77
  veh_fuel_end: float | None = None
66
78
  lat: float
67
79
  lon: float
68
- city: str
69
- state: str
70
- rg_brg: float
71
- rg_km: float
80
+ city: str | None = None
81
+ state: str | None = None
82
+ rg_brg: float | None = None
83
+ rg_km: float | None = None
72
84
  rg_match: bool
73
85
  end_type: str
74
86
  driver: UserSummary | None = None
@@ -26,17 +26,26 @@ Everything else mirrors verbatim: the unit-suffixed int family
26
26
  (``distanceMeters``, ``fuelConsumedMl``, ``tollMeters``) and the
27
27
  odometer pair keep provider units untouched; ``driverId`` is an int
28
28
  whose ``0`` is the UNASSIGNED sentinel (110/725) -- mirrored verbatim,
29
- never nulled or interpreted. ``assetIds``/``codriverIds`` were observed
30
- ONLY EMPTY across all 725 records; they are typed ``list[int]`` --
31
- the int-id family, in the ``list[scalar]`` form the records layer's
32
- schema derivation represents (DESIGN §9; the §9 pipeline has no tuple
33
- form) -- so a first non-empty capture lands as data, not a crash.
34
-
35
- The record does NOT echo the requested ``vehicleId``: per-vehicle
36
- attribution lives in the request parameter (the roster fan-out member),
37
- not on the wire record. The response *wrapper* (the ``{"trips": [...]}``
38
- envelope, unpaginated) is the endpoints layer's decoder concern; this
39
- module mirrors only the inner per-trip object.
29
+ never nulled or interpreted. ``assetIds``/``codriverIds`` are typed
30
+ ``list[int]`` -- the int-id family, in the ``list[scalar]`` form the
31
+ records layer's schema derivation represents (DESIGN §9; the §9
32
+ pipeline has no tuple form). The 725-trip census observed both EMPTY on
33
+ every record; a larger live pull (2026-07-22) then returned ``assetIds``
34
+ populated on a substantial minority of trips (its elements are attached
35
+ assets -- trailers/equipment -- not the trip's own vehicle), while
36
+ ``codriverIds`` stayed empty. The ``list[int]`` typing anticipated
37
+ exactly that, so a non-empty capture lands as data, not a crash -- the
38
+ census sized the shape, it never bounded the population.
39
+
40
+ The wire record does NOT echo the requested ``vehicleId``: per-vehicle
41
+ attribution is the request parameter (the roster fan-out member), not a
42
+ wire field. So ``vehicle_id`` is the one SYNTHESIZED field on this
43
+ otherwise-pure mirror -- ``SamsaraTripsPageDecoder`` stamps it off the
44
+ sent spec before validation, mirrored as a string to match
45
+ ``Vehicle.id`` for a direct join to the vehicles listing. The response
46
+ *wrapper* (the ``{"trips": [...]}`` envelope, unpaginated) is the
47
+ endpoints layer's decoder concern; this module mirrors only the inner
48
+ per-trip object, plus that one synthesized identity.
40
49
 
41
50
  Wire keys are camelCase; fields are snake_case via the ``to_camel``
42
51
  alias generator (``startMs``/``endMs`` carry explicit aliases, since
@@ -133,12 +142,16 @@ class TripAddress(ResponseModel):
133
142
  class Trip(ResponseModel):
134
143
  """One Samsara vehicle trip, overlap-retrieved per (vehicle, window).
135
144
 
136
- A pure mirror of the captured fields (module docstring). Field
137
- semantics and units are Samsara's; no value is derived or
138
- interpreted here. The requested ``vehicleId`` is not echoed on the
139
- record.
145
+ A near-pure mirror of the captured fields (module docstring): field
146
+ semantics and units are Samsara's, no value derived or interpreted
147
+ -- the one exception is ``vehicle_id``, synthesized because the wire
148
+ record does not echo the requested ``vehicleId`` (stamped off the
149
+ sent spec by ``SamsaraTripsPageDecoder``).
140
150
 
141
151
  Attributes:
152
+ vehicle_id: The fan-out vehicle this trip belongs to, stamped
153
+ from the request's ``vehicleId`` -- the wire record never
154
+ echoes it; a numeric string, matching ``Vehicle.id``.
142
155
  start_time: Trip start, recovered from the wire's epoch-ms
143
156
  ``startMs`` -- the endpoint's event time (start-anchored
144
157
  ownership, DESIGN §4).
@@ -158,10 +171,11 @@ class Trip(ResponseModel):
158
171
  end_location: Reverse-geocoded end location string.
159
172
  start_coordinates: The start ``{latitude, longitude}`` block.
160
173
  end_coordinates: The end ``{latitude, longitude}`` block.
161
- asset_ids: Attached asset ids; observed ONLY EMPTY across all
162
- 725 census records.
163
- codriver_ids: Co-driver ids; observed ONLY EMPTY across all 725
164
- census records.
174
+ asset_ids: Attached asset ids (trailers/equipment, not the
175
+ trip's own vehicle); empty across the 725-trip census, then
176
+ populated on a minority of trips in a larger live pull.
177
+ codriver_ids: Co-driver ids; empty across the 725-trip census
178
+ and the larger live pull alike.
165
179
  start_address: The matched start address/geofence block
166
180
  (177/725); null when no defined address matched.
167
181
  end_address: The matched end address/geofence block (185/725);
@@ -170,6 +184,14 @@ class Trip(ResponseModel):
170
184
 
171
185
  model_config = ConfigDict(alias_generator=to_camel)
172
186
 
187
+ # The fan-out vehicle, synthesized: the wire record does not echo the
188
+ # requested vehicleId, so SamsaraTripsPageDecoder stamps it off the
189
+ # sent spec before validation (module docstring). Mirrored as a
190
+ # string, matching Vehicle.id, so it joins the vehicles listing
191
+ # directly; the to_camel generator aliases vehicle_id -> vehicleId,
192
+ # which is the decoder's stamp key.
193
+ vehicle_id: str
194
+
173
195
  # The trip interval (epoch-ms recovered, module docstring).
174
196
  start_time: _EpochMillisecondsDatetime = Field(alias='startMs')
175
197
  end_time: _EpochMillisecondsDatetime = Field(alias='endMs')
@@ -25,6 +25,7 @@ from fleetpull.network.decoders.samsara import (
25
25
  SamsaraVehicleSeriesPageDecoder,
26
26
  )
27
27
  from fleetpull.network.decoders.samsara_reports import SamsaraWindowReportPageDecoder
28
+ from fleetpull.network.decoders.samsara_trips import SamsaraTripsPageDecoder
28
29
  from fleetpull.network.decoders.single_page import SinglePageDecoder
29
30
 
30
31
  __all__: list[str] = [
@@ -34,6 +35,7 @@ __all__: list[str] = [
34
35
  'MotiveWrappedListPageDecoder',
35
36
  'MotiveWrappedSinglePageDecoder',
36
37
  'SamsaraCursorPageDecoder',
38
+ 'SamsaraTripsPageDecoder',
37
39
  'SamsaraVehicleSeriesPageDecoder',
38
40
  'SamsaraWindowReportPageDecoder',
39
41
  'SinglePageDecoder',
@@ -0,0 +1,105 @@
1
+ # src/fleetpull/network/decoders/samsara_trips.py
2
+ """The Samsara trips page decoder: unpaginated records, vehicle-stamped.
3
+
4
+ The trips surface (``GET /v1/fleet/trips``) is a per-vehicle fan-out
5
+ whose response does NOT echo the requested ``vehicleId`` -- the inner
6
+ per-trip object carries no vehicle field of any kind (2026-07-20
7
+ census; re-proven at scale 2026-07-22, where every stored trip lacked a
8
+ vehicle identity). The vehicle a trip belongs to is therefore the
9
+ fan-out member the request asked for, not anything on the wire, so this
10
+ decoder STAMPS every trip with the ``vehicleId`` copied VERBATIM from
11
+ the SENT spec's own query param. It is the report family's
12
+ sent-spec-sourced stamp (``SamsaraWindowReportPageDecoder``) applied to
13
+ a fan-out member instead of a window: without it the stored row cannot
14
+ be attributed to a vehicle.
15
+
16
+ The envelope is ``{"trips": [...]}`` with no pagination of any kind --
17
+ one response per (vehicle, window) -- so the page is always terminal
18
+ (the ``SinglePageDecoder`` shape it supersedes for this surface, now
19
+ that the terminal page must also carry the member stamp). Decoder logic
20
+ deliberately resembles its siblings without sharing code.
21
+ """
22
+
23
+ from dataclasses import dataclass
24
+
25
+ from fleetpull.exceptions import ProviderResponseError
26
+ from fleetpull.network.contract import (
27
+ DecodedPage,
28
+ PageAdvance,
29
+ RequestSpec,
30
+ require_record_list,
31
+ )
32
+ from fleetpull.vocabulary import JsonValue
33
+
34
+ __all__: list[str] = ['SamsaraTripsPageDecoder']
35
+
36
+
37
+ @dataclass(frozen=True, slots=True)
38
+ class SamsaraTripsPageDecoder:
39
+ """Decode Samsara's unpaginated trips page, stamping the fan-out vehicle.
40
+
41
+ The trips surface returns a top-level list under ``records_key`` with
42
+ no pagination, so every page is terminal. The per-trip wire object
43
+ carries no vehicle identity; the vehicle is the fan-out member the
44
+ request asked for, so each record is stamped with ``member_key``
45
+ copied verbatim from the SENT spec's own query param -- the
46
+ ``SamsaraWindowReportPageDecoder`` sent-spec stamp, sourcing a
47
+ fan-out member rather than a window.
48
+
49
+ The stamp wins any (census-impossible) key collision: it is the
50
+ row's REQUIRED vehicle identity, exactly the vehicle asked of the
51
+ provider, and a colliding future wire key must never silently
52
+ supplant it -- the report family's stamp-wins order, the inverse of
53
+ the series decoder's reading-keys-win.
54
+
55
+ Attributes:
56
+ records_key: The top-level key holding the trip record list.
57
+ member_key: The fan-out member's query-param name (the roster
58
+ ``member_key``); read off the SENT spec and stamped onto
59
+ every record under the SAME key, which is also the response
60
+ model's alias for the stamped ``vehicle_id`` field. One
61
+ token binds the request param, the stamp, and the model
62
+ alias, so no translation seam can drift.
63
+ """
64
+
65
+ records_key: str
66
+ member_key: str
67
+
68
+ def first_request(self, spec: RequestSpec) -> RequestSpec:
69
+ """Return the base spec unchanged; the trips surface is unpaginated."""
70
+ return spec
71
+
72
+ def decode_page(self, sent: RequestSpec, envelope: JsonValue) -> DecodedPage:
73
+ """Extract the records, stamp each with the sent vehicle; terminal.
74
+
75
+ Args:
76
+ sent: The spec that produced this page; supplies the fan-out
77
+ member (``member_key``) stamped onto every record.
78
+ envelope: The parsed response body.
79
+
80
+ Returns:
81
+ One record per trip, each carrying the ``member_key`` stamp,
82
+ and a terminal verdict -- there is no continuation.
83
+
84
+ Raises:
85
+ ProviderResponseError: The sent spec lacks the ``member_key``
86
+ param (a wiring bug -- a fan-out request always carries
87
+ its member -- never silently unstamped, vehicle-less
88
+ rows), or the record-bearing shape is structurally
89
+ violating.
90
+ """
91
+ params = sent.params or {}
92
+ if self.member_key not in params:
93
+ raise ProviderResponseError(
94
+ detail=(
95
+ f'sent spec lacks the {self.member_key!r} fan-out member '
96
+ 'to stamp trip rows with'
97
+ )
98
+ )
99
+ vehicle_stamp = {self.member_key: params[self.member_key]}
100
+ records = require_record_list(envelope, self.records_key)
101
+ stamped = [{**record, **vehicle_stamp} for record in records]
102
+ return DecodedPage(
103
+ records=stamped,
104
+ advance=PageAdvance(next_spec=None, durable_progress=None),
105
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fleetpull
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Pull fleet telematics data from provider APIs (Motive, Samsara, GeoTab) into typed polars DataFrames and parquet: retrieval, dtype coercion, and light structural normalization — no assumed end use.
5
5
  Author-email: Andrew Jordan <andrewjordan3@gmail.com>
6
6
  Maintainer-email: Andrew Jordan <andrewjordan3@gmail.com>
@@ -169,6 +169,7 @@ src/fleetpull/network/decoders/motive.py
169
169
  src/fleetpull/network/decoders/motive_reports.py
170
170
  src/fleetpull/network/decoders/samsara.py
171
171
  src/fleetpull/network/decoders/samsara_reports.py
172
+ src/fleetpull/network/decoders/samsara_trips.py
172
173
  src/fleetpull/network/decoders/single_page.py
173
174
  src/fleetpull/network/limits/__init__.py
174
175
  src/fleetpull/network/limits/bucket_math.py
File without changes
File without changes
File without changes