Skip to content

Step 5: dealer, VIN, usage models + validators + public exports#2

Merged
whitewalls86 merged 2 commits into
masterfrom
step-5-models
Jun 12, 2026
Merged

Step 5: dealer, VIN, usage models + validators + public exports#2
whitewalls86 merged 2 commits into
masterfrom
step-5-models

Conversation

@whitewalls86

Copy link
Copy Markdown
Owner

Summary

  • Adds dealers.py, vins.py, and usage.py model files (step 5 of the implementation plan)
  • Populates models/__init__.py and visor/__init__.py with all public model exports
  • Adds 50-test tests/test_models.py covering response parsing and request validators

What's in this PR

New files

  • src/visor/models/dealers.pyDealerFilter, DealerAddress, DealerSummary, DealerDetail, DealersPage
  • src/visor/models/vins.pyVinDetail (latest_listing typed as ListingSnapshot)
  • src/visor/models/usage.pyUsageRecord, UsageTotals, UsageMeta, UsageSummary
  • tests/test_models.py — 50 response-parsing and validator tests

Updated files

  • src/visor/models/__init__.py — re-exports all public model types
  • src/visor/__init__.py — exports exceptions + all model types
  • src/visor/models/facets.pyfacet_value_limit max-100 validator; model_validator requiring exactly one categorical facet when metric is set
  • src/visor/models/dealers.pylimit max-100 validator; dealer_id list length max-100 validator

Validator decisions

DealerFilter limits — both limit and dealer_id are capped at 100 per the API docs, matching the existing pattern in ListingsFilter.

FacetsFilter.metric + categorical facet — when metric is set, the model validator requires exactly one categorical facet (any facet that is not price, msrp, miles, or days_on_market). Those four are the range facets (they produce range_facets in the response, not bucketed facets). The rule rejects zero categorical facets (nothing to group by) and two or more (ambiguous grouping).

Test plan

  • pytest — 50 tests, all passing
  • ruff check . — clean
  • ruff format --check . — clean
  • mypy src/ — clean

🤖 Generated with Claude Code

whitewalls86 and others added 2 commits June 12, 2026 15:54
Implements step 5 of the implementation plan:
- src/visor/models/dealers.py: DealerFilter, DealerAddress, DealerSummary, DealerDetail, DealersPage
- src/visor/models/vins.py: VinDetail (latest_listing uses ListingSnapshot)
- src/visor/models/usage.py: UsageRecord, UsageTotals, UsageMeta, UsageSummary
- src/visor/models/__init__.py: re-exports all public model types
- src/visor/__init__.py: exports exceptions and all model types
- tests/test_models.py: 22 response-parsing tests covering all new models

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DealerFilter: enforce limit <= 100 and dealer_id list length <= 100
- FacetsFilter: enforce facet_value_limit <= 100; add model_validator
  requiring exactly one categorical facet when metric is set
- src/visor/__init__.py: add missing public exports (DealerAddress,
  DealerRef, FacetBucket, FacetsData, UsageMeta, UsageRecord, UsageTotals)
- tests/test_models.py: add 10 tests covering the new validators

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@whitewalls86
whitewalls86 merged commit e8dc38c into master Jun 12, 2026
2 checks passed
@whitewalls86
whitewalls86 deleted the step-5-models branch June 12, 2026 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant