diff --git a/CHANGELOG.md b/CHANGELOG.md index f7b10b1..4f2ae55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## v0.3.0 (2024-02-19) + +[GitHub release](https://github.com/davidpeckham/vin/releases/tag/v0.3.0) + +### New Features + +* Decode the make, model, series, and trim +* Supports passenger cars, multipurpose vehicles, and light trucks manufactured since 1980 +* Performance benchmarks + +### Fixes + +* Correctly determines the model year for older vehicles + ## v0.2.0 (2024-02-03) [GitHub release](https://github.com/davidpeckham/vin/releases/tag/v0.2.0) diff --git a/README.md b/README.md index 82ca1aa..19ad52c 100644 --- a/README.md +++ b/README.md @@ -7,35 +7,52 @@ ----- -**Contents** - -- [Why use VIN?](#why-use-vin) -- [Vehicle Identification Number](#vehicle-identification-number) -- [Vehicle Data](#vehicle-data) -- [Installation](#installation) -- [License](#license) - -VIN validates Vehicle Identification Numbers and decodes the vehicle's manufacturer, make, model, and model year. +``VIN`` validates Vehicle Identification Numbers and decodes the vehicle's manufacturer, make, model, series, trim, and model year. >>> from vin import VIN + >>> VIN('KNDCE3LG2L5073161').description + '2020 Kia Niro EX Premium' + >>> vin("5FNYF5H59HB011946").manufacturer Honda + >>> vin("5FNYF5H59HB011946").model_year + 2017 + >>> vin("YT9NN1U14KA007175").manufacturer Koenigsegg - >>> vin("5FNYF5H59HB011946").model_year - 2017 +``VIN`` supports passenger vehicles manufactured since 1980: + +* Passenger Cars +* Multipurpose Passenger Vehicle (MPV) +* Light Trucks + +``VIN`` does not currently support: + +* Buses +* Heavy Trucks +* Incomplete Vehicles +* Low Speed Vehicles (LSV) +* Motorcycles +* Off Road Vehicles +* Trailers ## Why use VIN? -- **Accurate** — Vehicle information is provided by the National Highway Traffic Safety Administration. -- **Fast** — Vehicle data is included and periodically updated, so validation and decoding are fast. +- **Accurate** — Uses U.S. National Highway Traffic Safety Administration vehicle data. +- **Fast** — Validate and decode 1,500 VINs per second. + +## Installation + +Use ``pip`` to install the library: + + $ pip install vin ## Vehicle Identification Number -A ``VIN`` is a unique 17-character Vehicle Identification Number. +A ```VIN``` is a unique 17-character Vehicle Identification Number. * Uniquely identifies vehicles manufactured for sale or use in the United States since 1980 * Assigned by vehicle manufacturers @@ -65,17 +82,10 @@ plant where the vehicle was made, and the vehicle's serial number. For more information, see the [VIN specification](https://www.ecfr.gov/current/title-49/subtitle-B/chapter-V/part-565). -Installation ------------- - -Use ``pip`` to install the library: - - $ pip install vin - ## Vehicle Data Vehicle data is provided by the U.S. National Highway Traffic Safety Administration (NHTSA) [Product Information Catalog and Vehicle Listing (vPIC)](https://vpic.nhtsa.dot.gov). ## License -`VIN` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license. \ No newline at end of file +``VIN`` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license. \ No newline at end of file diff --git a/docs/hooks.py b/docs/hooks.py index 38a0e01..de27025 100644 --- a/docs/hooks.py +++ b/docs/hooks.py @@ -1,5 +1,6 @@ import shutil -def copy_history(*args, **kwargs): +def copy_docs(*args, **kwargs): shutil.copy("CHANGELOG.md", "docs/changelog.md") + shutil.copy("README.md", "docs/index.md") diff --git a/docs/index.md b/docs/index.md index 4b7ee6a..19ad52c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,30 +7,55 @@ ----- -VIN validates Vehicle Identification Numbers and decodes the vehicle's manufacturer, make, model, and model year. +``VIN`` validates Vehicle Identification Numbers and decodes the vehicle's manufacturer, make, model, series, trim, and model year. >>> from vin import VIN + >>> VIN('KNDCE3LG2L5073161').description + '2020 Kia Niro EX Premium' + >>> vin("5FNYF5H59HB011946").manufacturer Honda + >>> vin("5FNYF5H59HB011946").model_year + 2017 + >>> vin("YT9NN1U14KA007175").manufacturer Koenigsegg - >>> vin("5FNYF5H59HB011946").model_year - 2017 +``VIN`` supports passenger vehicles manufactured since 1980: + +* Passenger Cars +* Multipurpose Passenger Vehicle (MPV) +* Light Trucks + +``VIN`` does not currently support: + +* Buses +* Heavy Trucks +* Incomplete Vehicles +* Low Speed Vehicles (LSV) +* Motorcycles +* Off Road Vehicles +* Trailers ## Why use VIN? -- **Accurate** — Vehicle information is provided by the National Highway Traffic Safety Administration. -- **Fast** — Vehicle data is included and periodically updated, so validation and decoding are fast. +- **Accurate** — Uses U.S. National Highway Traffic Safety Administration vehicle data. +- **Fast** — Validate and decode 1,500 VINs per second. + +## Installation + +Use ``pip`` to install the library: + + $ pip install vin ## Vehicle Identification Number -A ``VIN`` is a unique 17-character Vehicle Identification Number. +A ```VIN``` is a unique 17-character Vehicle Identification Number. -* Assigned by vehicle manufacturers * Uniquely identifies vehicles manufactured for sale or use in the United States since 1980 +* Assigned by vehicle manufacturers * Governed by the U.S. National Highway Traffic Safety Administration (NHTSA) The structure of the VIN is: @@ -57,18 +82,10 @@ plant where the vehicle was made, and the vehicle's serial number. For more information, see the [VIN specification](https://www.ecfr.gov/current/title-49/subtitle-B/chapter-V/part-565). -Installation ------------- - -Use ``pip`` to install the library: - - $ pip install vin - ## Vehicle Data Vehicle data is provided by the U.S. National Highway Traffic Safety Administration (NHTSA) [Product Information Catalog and Vehicle Listing (vPIC)](https://vpic.nhtsa.dot.gov). ## License -VIN is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license. - +``VIN`` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license. \ No newline at end of file diff --git a/hatch.toml b/hatch.toml index 2b1ed3d..4fea455 100644 --- a/hatch.toml +++ b/hatch.toml @@ -2,12 +2,13 @@ dependencies = [ "freezegun==1.2.*", "pytest-cov==4.1.*", + "pytest-benchmark==4.0.*", "pytest==7.3.*", "parametrize_from_file" ] [envs.default.scripts] -test = "pytest {args:.}" +test = "pytest {args:.} --benchmark-autosave" cov-test = "pytest --cov {args:vin} --cov-report=term-missing --cov-report=xml" [envs.lint] @@ -49,6 +50,7 @@ dependencies = [ # Validation # https://github.com/linkchecker/linkchecker/pull/669#issuecomment-1267236287 "linkchecker @ git+https://github.com/linkchecker/linkchecker.git@d9265bb71c2054bf57b8c5734a4825d62505c779", + "black" ] [envs.docs.scripts] build = "mkdocs build --clean --strict" diff --git a/mkdocs.yml b/mkdocs.yml index bb36660..6cd3e57 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -67,7 +67,7 @@ plugins: merge_init_into_class: true mkdocs-simple-hooks: hooks: - on_pre_build: 'docs.hooks:copy_history' + on_pre_build: 'docs.hooks:copy_docs' markdown_extensions: - admonition diff --git a/pyproject.toml b/pyproject.toml index 37c1a8c..1d76097 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ path = "src/vin/__about__.py" [tool.hatch.envs.default] dependencies = [ "coverage[toml]>=6.5", - "pytest", + "pytest" ] [tool.hatch.envs.default.scripts] test = "pytest {args:tests}" diff --git a/src/vin/__about__.py b/src/vin/__about__.py index 2b141a2..cbdabaa 100644 --- a/src/vin/__about__.py +++ b/src/vin/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present David Peckham # # SPDX-License-Identifier: MIT -__version__ = "0.2.0" +__version__ = "0.3.0" diff --git a/src/vin/__init__.py b/src/vin/__init__.py index 639888a..07f67de 100644 --- a/src/vin/__init__.py +++ b/src/vin/__init__.py @@ -9,9 +9,8 @@ # ruff: noqa: TRY003, EM101, EM102 from datetime import date -from importlib.resources import files -from typing import Final +from vin.constants import CARS_AND_LIGHT_TRUCKS from vin.constants import VIN_CHARACTER_VALUES from vin.constants import VIN_CHARACTERS from vin.constants import VIN_CHECK_DIGIT_CHARACTERS @@ -74,13 +73,8 @@ class VIN: """ - CARS_AND_LIGHT_TRUCKS: Final[list[str]] = ( - files("vin").joinpath("cars-and-light-trucks.csv").read_text().splitlines() - ) - """WMI that make cars and light trucks (used to determine model year)""" - - def __init__(self, vin: str, decode=True, fix_check_digit=False) -> None: - """Initialize a VIN. + def __init__(self, vin: str, decode: bool = True, fix_check_digit: bool = False) -> None: + """Validates the VIN and decodes vehicle information. Args: vin: The 17-digit Vehicle Identification Number. @@ -160,11 +154,9 @@ def calculate_check_digit(cls, vin: str) -> str: """ total = 0 - for n in range(VIN_LENGTH): - if n == VIN_CHECK_DIGIT_POSITION: - continue - letter = vin[n] - total = total + VIN_CHARACTER_VALUES[letter] * VIN_POSITION_WEIGHTS[n] + for position, letter in enumerate(vin): + if position != VIN_CHECK_DIGIT_POSITION: + total += VIN_CHARACTER_VALUES[letter] * VIN_POSITION_WEIGHTS[position] return VIN_CHECK_DIGIT_CHARACTERS[total % 11] @property @@ -371,18 +363,10 @@ def descriptor(self) -> str: """The part of the VIN used to lookup make, model, and other vehicle attributes in NHTSA vPIC. - The descriptor is 11 characters for a mass-market manufacturer. - For specialized manufacturers, the descriptor is 14 characters so - that it includes the second half of the WMI. - Returns: - str: the 11- or 14-character descriptor for this VIN + str: the 14-character descriptor for this VIN """ return f"{self._vin[3:8]}|{self._vin[9:]}" - # if self._vin[2] == "9": - # return descriptor[:14] - # else: - # return descriptor[:11] def _decode_model_year(self) -> int: """The model year as encoded in the VIN. @@ -394,11 +378,11 @@ def _decode_model_year(self) -> int: uses information from NHTSA vPIC to determine the actual model year. Returns: - The vehicle model year. May be negative if the VIN alone isn't - sufficient to determine the model year. When this happens, the - actual model year is likely the absolute value of this model year, - or 30 years earlier. To find the actual model year, look up the VIN - VIN details first with the later model year and then the earlier + The vehicle model year. May be negative if the VIN alone isn't \ + sufficient to determine the model year. When this happens, the \ + actual model year is likely the absolute value of this model year, \ + or 30 years earlier. To find the actual model year, look up the VIN \ + VIN details first with the later model year and then the earlier \ model year -- only one of these is likely to return a result. Examples: @@ -428,7 +412,7 @@ def _decode_model_year(self) -> int: assert model_year > 0 - if self.wmi in self.CARS_AND_LIGHT_TRUCKS: + if self.wmi in CARS_AND_LIGHT_TRUCKS: if self._vin[6].isdigit(): # cars and light trucks manufactured on or before April 30, 2009 (1980 to 2009) model_year -= 30 diff --git a/src/vin/cars-and-light-trucks.csv b/src/vin/cars-and-light-trucks.csv deleted file mode 100644 index a44751e..0000000 --- a/src/vin/cars-and-light-trucks.csv +++ /dev/null @@ -1,568 +0,0 @@ -12A -137 -177 -18L -19U -19V -19X -1A4 -1A8 -1A9398 -1A9539 -1A9841 -1A9997 -1AC -1AM -1B3 -1B4 -1B8 -1B9884 -1BB -1C3 -1C4 -1C8 -1C9291 -1C9369 -1C9396 -1C9416 -1C9453 -1C9516 -1C9519 -1D4 -1D8 -1D9738 -1E3 -1E9101 -1E9104 -1E9333 -1E9465 -1E9466 -1E9581 -1E9690 -1F1 -1F7 -1F9306 -1F9406 -1FA -1FL -1FM -1G0 -1G1 -1G2 -1G3 -1G4 -1G5 -1G6 -1G7 -1G8 -1G9231 -1G9297 -1GH -1GK -1GM -1GN -1GY -1H9455 -1H9610 -1H9814 -1HG -1J4 -1J8 -1J9123 -1JC -1JT -1K9303 -1K9436 -1L1 -1L9067 -1L9155 -1L9234 -1LN -1M9227 -1M9606 -1M9682 -1M9842 -1ME -1MR -1N4 -1N6 -1N9295 -1NX -1P3 -1P4 -1P9065 -1P9213 -1P9443 -1P9481 -1P9654 -1P9794 -1P9843 -1R9059 -1R9595 -1R9788 -1R9869 -1R9885 -1S9208 -1S9547 -1S9557 -1S9566 -1S9842 -1S9944 -1S9S10 -1S9S20 -1T9979 -1U9163 -1V1 -1V2 -1V9045 -1V9048 -1V9179 -1V9258 -1VW -1W9097 -1W9303 -1W9492 -1WT -1WV -1WW -1XA -1Y1 -1Y9018 -1YV -1Z4 -1Z6 -1Z8 -1ZV -1ZW -2A3 -2A4 -2A8 -2A9191 -2B3 -2B4 -2B8 -2BA -2BC -2C1 -2C2 -2C3 -2C4 -2C8 -2CA -2CC -2CG -2CK -2CM -2CN -2CT -2D4 -2D8 -2E3 -2E4 -2FA -2FM -2G1 -2G2 -2G3 -2G4 -2G6 -2G7 -2G8 -2GK -2GN -2HG -2HH -2HK -2HN -2J4 -2LM -2LN -2ME -2MR -2P3 -2P4 -2S2 -2S3 -2T1 -2T2 -2T3 -2V4 -2V8 -2XM -3A4 -3A8 -3B3 -3B4 -3B8 -3C3 -3C4 -3C8 -3CA -3CZ -3D4 -3D8 -3E3 -3E4 -3FA -3FM -3G0 -3G1 -3G2 -3G3 -3G4 -3G5 -3G7 -3GK -3GM -3GN -3GP -3GS -3GY -3HG -3J4 -3KM -3KP -3LN -3MA -3MD -3ME -3MF -3MV -3MW -3MY -3MZ -3N1 -3N8 -3P3 -3P4 -3PC -3VV -3VW -43C -4A3 -4A4 -4A9043 -4B3 -4B9070 -4B9079 -4B9146 -4C3 -4C9014 -4C9034 -4C9152 -4C9333 -4C9561 -4C9687 -4CR -4E3 -4F2 -4G1 -4G2 -4G3 -4G5 -4GD -4HM -4HR -4JG -4M2 -4M9072 -4N2 -4NT -4NU -4P3 -4S2 -4S3 -4S4 -4S6 -4S9105 -4S9263 -4S9407 -4S9449 -4S9454 -4S9489 -4S9520 -4S9542 -4S9544 -4T1 -4T3 -4T4 -4T9015 -4T9228 -4T9343 -4US -4W5 -50E -50G -514 -520 -523 -52S -53G -53J -53T -54T -54W -55S -56N -57W -58A -58M -5AC -5BJ -5BP -5CX -5ES -5FN -5FR -5G2 -5G3 -5G8 -5GA -5GD -5GR -5GT -5GZ -5J6 -5J8 -5KB -5KC -5L1 -5LM -5N1 -5N3 -5NM -5NP -5S3 -5TD -5UM -5UX -5XX -5XY -5Y2 -5YF -5YJ -5YM -6G1 -6G2 -6G3 -6MM -6MP -7FA -7G0 -7G6 -7HT -7JR -7KZ -7MM -7MU -7NY -7P2 -7PD -7SA -7SV -7TN -7WA -7Z0 -849001 -8BT -9BW -ADM -J81 -J87 -J8Z -JA3 -JA4 -JAA -JAB -JAC -JAE -JB3 -JB4 -JB7 -JC1 -JD1 -JD2 -JE3 -JE4 -JF1 -JF2 -JF3 -JF4 -JG1 -JG2 -JG7 -JH4 -JHL -JHM -JJ3 -JM1 -JM2 -JM3 -JN1 -JN6 -JN8 -JNK -JNR -JP3 -JP4 -JP7 -JR2 -JS2 -JS3 -JT2 -JT3 -JT4 -JT5 -JT6 -JT8 -JTD -JTE -JTH -JTJ -JTK -JTL -JTM -JTN -KL1 -KL2 -KL4 -KL5 -KL7 -KL8 -KLA -KM8 -KMH -KMT -KMU -KNA -KND -KNJ -KNM -KPH -KPS -LA9HZG -LES -LFP -LGX -LM5 -LPS -LRB -LRE -LSG -LVP -LVY -LYV -MAJ -MCV -ML3 -MN3 -MP3 -NMT -PFD -RLL -SA9004 -SA9005 -SA9A11 -SA9J00 -SAD -SAJ -SAL -SAT -SAX -SBM -SC6 -SCA -SCB -SCC -SCF -SCR -SD7 -SD8 -SFZ -SHH -SHS -SJA -SJK -SJZ -SLA -TMC -TRU -U5Y -V39AB8 -VCF -VF1 -VF3 -VF9795 -VL4 -VNK -VX1 -W04 -W06 -W08 -W09R06 -W09R09 -W0L -W0V -W1K -W1N -W1W -W2W -WA1 -WAP -WAU -WB5 -WBA -WBS -WBX -WBY -WD4 -WD5 -WD8 -WDB -WDC -WDD -WDR -WF0 -WF1 -WME -WMW -WMZ -WP0 -WP1 -WU1 -WUA -WV2 -WVG -WVW -WZ1 -X89AC5 -XL9363 -XL9486 -XZ1 -YH4 -YK1 -YS3 -YSM -YSR -YT9007 -YV1 -YV4 -YYC -ZA9A12 -ZA9D39 -ZA9F76 -ZA9M91 -ZAC -ZAM -ZAR -ZAS -ZC2 -ZFA -ZFB -ZFD -ZFF -ZFR -ZHW -ZN6 -ZPB -ZSG diff --git a/src/vin/constants.py b/src/vin/constants.py index d42d39c..70aedcc 100644 --- a/src/vin/constants.py +++ b/src/vin/constants.py @@ -1,3 +1,8 @@ +from typing import Final + +from vin.database import get_wmis_for_cars_and_light_trucks + + VIN_LENGTH: int = 17 VIN_CHECK_DIGIT_POSITION: int = 8 @@ -83,3 +88,6 @@ VIN_MODEL_YEAR_CHARACTERS = list(set(VIN_MODEL_YEAR_CODES.values())) VIN_CHECK_DIGIT_CHARACTERS: str = "0123456789X" + +CARS_AND_LIGHT_TRUCKS: Final[list[str]] = get_wmis_for_cars_and_light_trucks() +"""WMI that make cars and light trucks (used to determine model year)""" diff --git a/src/vin/database.py b/src/vin/database.py index 5514817..dac6eef 100644 --- a/src/vin/database.py +++ b/src/vin/database.py @@ -12,9 +12,6 @@ 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 - # found = re.match(pattern, value) is not None - # print(f"{value=} {pattern=} {'found' if found else '---'}") - # return found connection = sqlite3.connect(DATABASE_PATH, detect_types=sqlite3.PARSE_DECLTYPES) @@ -27,13 +24,16 @@ def query(sql: str, args: tuple = ()) -> list[sqlite3.Row]: cursor = connection.cursor() results = cursor.execute(sql, args).fetchall() cursor.close() + return results - # print(sql) - print(args) - for result in results: - print(dict(result)) - return results +def get_wmis_for_cars_and_light_trucks() -> list[str]: + """Return a list of WMIs that manufacture cars and light trucks + + Returns: + list[str]: WMIs that make cars and light trucks + """ + return [result["wmi"] for result in query(sql=GET_WMI_FOR_CARS_AND_LIGHT_TRUCKS)] def lookup_vehicle(wmi: str, vds: str, model_year: int) -> dict | None: @@ -95,3 +95,19 @@ def lookup_vehicle(wmi: str, vds: str, model_year: int) -> dict | None: and ? between pattern.from_year and pattern.to_year and REGEXP(?, pattern.vds); """ + + +GET_WMI_FOR_CARS_AND_LIGHT_TRUCKS = """ +select + wmi.code as wmi +from + wmi +where + vehicle_type_id in (2, 7) -- Cars and MPVs + or ( -- light trucks + wmi.vehicle_type_id = 3 + and wmi.truck_type_id = 1 + ) +order by + wmi.code; +""" diff --git a/tests/benchmarks/__init__.py b/tests/benchmarks/__init__.py new file mode 100644 index 0000000..70e2375 --- /dev/null +++ b/tests/benchmarks/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2024-present David Peckham +# +# SPDX-License-Identifier: MIT diff --git a/tests/benchmarks/conftest.py b/tests/benchmarks/conftest.py new file mode 100644 index 0000000..4496d19 --- /dev/null +++ b/tests/benchmarks/conftest.py @@ -0,0 +1,114 @@ +import random + +import pytest + + +VEHICLES = [ + "1B4GP54RXVB379372", + "1B4HS28N41F549124", + "1B4HS28N51F542134", + "1B7HF16Y4TS518710", + "1C41JUEJ6NC004408", + "1C41JUEJ7NC002943", + "1C4GJ25372B521864", + "1C4GJWAG3DL544796", + "1FMCU14T3JU402061", + "1FMCU14T5JU402336", + "1FMCU14T5JU402756", + "1FTEF14N5KNB35920", + "1FTJW36F5TEA07453", + "1FTJW36F9TEA02868", + "1G1JC1440PZ215164", + "1G4GD5ED5BF334614", + "1G8ZF52801Z322733", + "1G8ZH1274XZ108296", + "1G8ZH1278XZ108219", + "1G8ZH5283YZ266971", + "1G8ZH528XYZ262643", + "1GCEC14W6TZ228585", + "1GCHK29U11E231511", + "1GCHK29U11E239270", + "1GCHK29U21E231713", + "1GKLVKED6AJ152841", + "1J4BA3H11AL173573", + "1J4BA3H12AL171413", + "1J4BA3H14AL172837", + "1J4FA29P3YP729948", + "1JCMR7841JT187822", + "1JCMR7846JT184561", + "1JCMR7848JT183928", + "1JCMR7849JT185834", + "1N6SD16S3NC346350", + "1N6SD16S6NC347945", + "2C3CCACG6CH275007", + "2C3CCACG9CH273929", + "2D8GP44L05R217097", + "2GCEC19Z0S1245490", + "2GCEC19Z1S1243263", + "2T1BR30E36C599972", + "2T1BR30E46C591864", + "3VWSD29M41M067176", + "4A3AK24F36E026691", + "4JGAB54E11A277331", + "4JGAB54E91A271941", + "4T1BB3EK5AU118081", + "5FNRL38247B006367", + "5FNRL38297B007384", + "5N1AL0MM8DC306971", + "5N3ZA0NE1AN908084", + "5N3ZA0NE8AN903142", + "5NPEB4AC9DH571382", + "5XYKTCA62DG346197", + "5XYZUDLB3DG001966", + "JH4DA1842JS002851", + "JH4DA3344JS014129", + "JH4DA3344KS007957", + "JH4DA9368PS006502", + "JH4DB1576LS806648", + "JH4DB1664NS003880", + "JH4DB1666NS007784", + "JH4DB1668NS001887", + "JH4DB7544RS009803", + "JH4DB7568SS006474", + "JH4DB7568SS009360", + "JH4DC4340RS003205", + "JH4DC4347RS007557", + "JH4KA2541HC021008", + "JH4KA2635HC013743", + "JH4KA3171KC014556", + "JH4KA3172KC019247", + "JH4KA3248JC013536", + "JH4KA3248JC018641", + "JH4KA453XKC037671", + "JH4KA4552JC049099", + "JH4KA465XJC001719", + "JH4KA7536MC014019", + "JM1FE173140136855", + "JM1FE173540134610", + "JN8AZ28R59T128050", + "JNKCV51F54M711589", + "JTHFE2C23A2509749", + "JTKKU4B40C1028652", + "KM8JN72D07U585496", + "KM8JN72DX7U583688", + "SCFFDECNXCGG14038", + "TRUWT28N251015796", + "TRUWT28N251018665", + "W06VR52R6WR227722", + "WAULF78K19N037307", + "WAULFAFR6DA001366", + "WAULFAFR8DA002471", + "WBSPM9C52BE209978", + "WP0CB29804U662557", + "WP0CB29874U669313", +] + + +@pytest.fixture() +def hundred_vehicles() -> list[str]: + return random.choices(VEHICLES, k=100) # noqa: S311 + + +@pytest.fixture() +def thousand_vehicles() -> list[str]: + return list(random.choices(VEHICLES, k=1000)) # noqa: S311 diff --git a/tests/benchmarks/test_benchmark.py b/tests/benchmarks/test_benchmark.py new file mode 100644 index 0000000..ddd3f08 --- /dev/null +++ b/tests/benchmarks/test_benchmark.py @@ -0,0 +1,17 @@ +from vin import VIN + + +def decode_vins(vehicles: list[str]) -> bool: + for vehicle in vehicles: + VIN(vehicle) + return True + + +def test_benchmark_100_vins(benchmark, hundred_vehicles): + result = benchmark(decode_vins, hundred_vehicles) + assert result + + +def test_benchmark_1000_vins(benchmark, thousand_vehicles): + result = benchmark(decode_vins, thousand_vehicles) + assert result