Skip to content

Commit

Permalink
fixes #3
Browse files Browse the repository at this point in the history
  • Loading branch information
davidpeckham committed Feb 21, 2024
1 parent c79f282 commit 44ca77f
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 54 deletions.
73 changes: 48 additions & 25 deletions src/vin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ def __init__(self, vin: str, decode: bool = True, fix_check_digit: bool = False)
return

@property
def body_style(self) -> str:
"""The body style.
def body_class(self) -> str:
"""The body class.
This is one of:
Expand Down Expand Up @@ -201,25 +201,30 @@ def body_style(self) -> str:
Examples:
>>> VIN("KNDCE3LG2L5073161").body_style
>>> VIN("KNDCE3LG2L5073161").body_class
'Sport Utility Vehicle (SUV)/Multi-Purpose Vehicle (MPV)'
"""
if self._body_style is None:
if self._body_class is None:
raise DecodingRequiredError()
return self._body_style
return self._body_class

@property
def description(self) -> str:
"""returns a one-line summary of the vehicle
Returns:
str: the model year, make, model, series, and trim
str: the model year, make, model, and series
Examples:
>>> VIN('KNDCE3LG2L5073161').description
'2020 Kia Niro EX Premium'
"""
return " ".join(
[
str(getattr(self, property))
for property in ["_model_year", "_make", "_model", "_series", "_trim"]
if getattr(self, property) is not None
if getattr(self, property)
]
)

Expand Down Expand Up @@ -276,9 +281,9 @@ def make(self) -> str:
Examples:
>>> VIN("5FNYF5H59HB011946").make
Honda
'Honda'
>>> VIN("YT9NN1U14KA007175").make
Koenigsegg
'Koenigsegg'
"""
if self._make is None:
raise DecodingRequiredError()
Expand All @@ -298,9 +303,9 @@ def manufacturer(self) -> str:
Examples:
>>> VIN("5FNYF5H59HB011946").manufacturer
American Honda Motor Co., Inc.
'American Honda Motor Co., Inc.'
>>> VIN("YT9NN1U14KA007175").manufacturer
Koenigsegg Automotive Ab
'Koenigsegg Automotive Ab'
"""
if self._manufacturer is None:
raise DecodingRequiredError()
Expand All @@ -320,9 +325,9 @@ def model(self) -> str:
Examples:
>>> VIN("5FNYF5H59HB011946").model
Pilot
'Pilot'
>>> VIN("YT9NN1U14KA007175").model
Regera
'Regera'
"""
if self._model is None:
raise DecodingRequiredError()
Expand Down Expand Up @@ -366,10 +371,28 @@ def series(self) -> str:
>>> VIN("5FNYF5H59HB011946").series
'EXL'
>>> VIN("YT9NN1U14KA007175").series
None
''
"""
return self._series

@property
def trim(self) -> str:
"""The vehicle trim name.
Returns:
The trim name.
Raises:
DecodingRequiredError: This property is only available when you choose to
decode the VIN. See VIN.__init__(..., decode=True).
Examples:
>>> VIN("5FNYF5H59HB011946").trim
''
"""
return self._trim

@property
def vds(self) -> str:
"""The Vehicle Description Section (VDS) of the VIN.
Expand Down Expand Up @@ -455,9 +478,9 @@ def wmi(self) -> str:
Examples:
>>> VIN("5FNYF5H59HB011946").wmi
5FN
'5FN'
>>> VIN("YT9NN1U14KA007175").wmi
YT9007
'YT9007'
"""
return f"{self._vin[:3]}{self._vin[11:14]}" if self._vin[2] == "9" else self._vin[:3]

Expand Down Expand Up @@ -555,15 +578,15 @@ def _decode_vin(self) -> None:

self._manufacturer = vehicle.get("manufacturer", None)
self._model_year = vehicle.get("model_year", None)
self._make = vehicle.get("make", None)
self._model = vehicle.get("model", None)
self._series = vehicle.get("series", None)
self._trim = vehicle.get("trim", None)
self._vehicle_type = vehicle.get("vehicle_type", None)
self._truck_type = vehicle.get("truck_type", None)
self._country = vehicle.get("country", None)
self._body_style = vehicle.get("body_style", None)
self._electrification_level = vehicle.get("electrification_level", None)
self._make = vehicle.get("make", "")
self._model = vehicle.get("model", "")
self._series = vehicle.get("series", "")
self._trim = vehicle.get("trim", "")
self._vehicle_type = vehicle.get("vehicle_type", "")
self._truck_type = vehicle.get("truck_type", "")
self._country = vehicle.get("country", "")
self._body_class = vehicle.get("body_class", "")
self._electrification_level = vehicle.get("electrification_level", "")

def __repr__(self) -> str:
return f"VIN({self!s})"
Expand Down
26 changes: 14 additions & 12 deletions src/vin/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

def regex(value, pattern) -> bool:
"""REGEXP shim for SQLite versions bundled with Python 3.11 and earlier"""
return re.match(pattern, value) is not None
match = re.match(pattern, value)
# print(f"value {value} pattern {pattern} {'match' if match else ''}")
return match is not None


connection = sqlite3.connect(DATABASE_PATH, detect_types=sqlite3.PARSE_DECLTYPES)
Expand Down Expand Up @@ -47,27 +49,27 @@ def lookup_vehicle(wmi: str, vds: str, model_year: int) -> dict | None:
"""
if results := query(sql=LOOKUP_VEHICLE_SQL, args=(wmi, model_year, vds)):
details = {
"series": None,
"trim": None,
# "series": None,
# "trim": None,
"model_year": model_year,
"body_style": None,
"electrification_level": None,
# "body_class": None,
# "electrification_level": None,
}
for row in results:
details.update(
{
k: row[k]
for k in [
"manufacturer",
"body_class",
"country",
"electrification_level",
"make",
"manufacturer",
"model",
"series",
"trim",
"vehicle_type",
"truck_type",
"country",
"body_style",
"electrification_level",
"vehicle_type",
]
if row[k] is not None
}
Expand All @@ -86,7 +88,7 @@ def lookup_vehicle(wmi: str, vds: str, model_year: int) -> dict | None:
vehicle_type.name as vehicle_type,
truck_type.name as truck_type,
country.name as country,
body_style.name as body_style,
body_class.name as body_class,
electrification_level.name as electrification_level
from
pattern
Expand All @@ -100,7 +102,7 @@ def lookup_vehicle(wmi: str, vds: str, model_year: int) -> dict | None:
join vehicle_type on vehicle_type.id = wmi.vehicle_type_id
left join truck_type on truck_type.id = wmi.truck_type_id
left join country on country.alpha_2_code = wmi.country
left join body_style on body_style.id = pattern.body_style_id
left join body_class on body_class.id = pattern.body_class_id
left join electrification_level on electrification_level.id = pattern.electrification_level_id
where
pattern.wmi = ?
Expand Down
Binary file modified src/vin/vehicle.db
Binary file not shown.
49 changes: 48 additions & 1 deletion tests/cars/test_decode.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import parametrize_from_file
import pytest
from vin import VIN


@parametrize_from_file
def test_decode(vin: str, model_year: int, make: str, model: str) -> None:
def test_decode(vin: str, model_year: int, make: str, model: str, body_class: str) -> None:
v = VIN(vin)
assert f"{model_year} {make} {model}".rstrip().replace(" ", " ") == v.description

if body_class:
assert body_class == v.body_class


def test_inconclusive_model_year() -> None:
"""This 1995 Chevy truck VIN model year character doesn't conclusively
Expand All @@ -18,3 +22,46 @@ def test_inconclusive_model_year() -> None:
def test_chevy_silverado() -> None:
v = VIN("1GCHK29U21E231713")
assert v.description == "2001 Chevrolet Silverado 2500 3/4 Ton"


def test_body_class() -> None:
v = VIN("KNAE55LC7J6018811")
assert v.body_class == "Hatchback/Liftback/Notchback"
v = VIN("KNAE55LC5J6035106")
assert v.body_class == "Hatchback/Liftback/Notchback"


def test_no_electrification_level() -> None:
v = VIN("1FM5K8HC8PGA15033")
assert v.electrification_level == ""
v = VIN("KNAE55LC5J6035106")
assert v.electrification_level == ""
v = VIN("4T1BK1EB3JU289187")
assert v.electrification_level == ""


def test_missing_make() -> None:
v = VIN("JTDBAMDE2MJ008197")

This comment has been minimized.

Copy link
@sshane

sshane Feb 21, 2024

Is there any way to get the make out of this like VPIC provides?

assert v.make == ""


def test_missing_model() -> None:
v = VIN("JTDBAMDE2MJ008197")
assert v.model == ""


def test_vpic_data_is_incomplete() -> None:
v = VIN("1G1F76E04K4140798")
assert v.make == ""


@pytest.mark.xfail(reason="vPIC dbo.Pattern seems to confuse the 1993 Integra and Legend trim data")
def test_vin_schema_collision() -> None:
v = VIN("JH4DA9368PS006502")
assert v.trim == "L"


@pytest.mark.xfail(reason="returns Low instead of LOW")
def test_wrong_trim_eclipse() -> None:
v = VIN("4A3AK24F36E026691")
assert v.trim == "LOW"
Loading

0 comments on commit 44ca77f

Please sign in to comment.