diff --git a/faker/providers/automotive/nl_NL/__init__.py b/faker/providers/automotive/nl_NL/__init__.py new file mode 100644 index 0000000000..3f54070934 --- /dev/null +++ b/faker/providers/automotive/nl_NL/__init__.py @@ -0,0 +1,79 @@ +import re +import string + +from .. import Provider as AutomotiveProvider + + +class Provider(AutomotiveProvider): + """Implement automotive provider for `nl_NL` locale. + + Sources: + - https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_the_Netherlands + - https://www.cbs.nl/en-gb/figures/detail/82044eng + + .. |license_plate_car| replace:: + :meth:`license_plate_car() ` + + .. |license_plate_motorbike| replace:: + :meth:`license_plate_motorbike() ` + """ + + # License formats for cars / other vehicles than motorbikes + license_formats = ( + # Format 6 + "##-%?-??", + + # Format 7 + "##-%??-#", + + # Format 8 + "#-@??-##", + + # Format 9 + "%?-###-?", + + # Format 10 + "%-###-??", + ) + + # License formats for motorbikes. + # According to CBS, approximately 10% of road vehicles in the Netherlands are motorbikes + license_formats_motorbike = ( + "M?-??-##", + "##-M?-??", + ) + + # Base first letters of format + license_plate_prefix_letters = "BDFGHJKLNPRSTVXZ" + + # For Format 8 (9-XXX-99) "BDFGHJLNPR" are not used, + # as to not clash with former export license plates + license_plate_prefix_letters_format_8 = "KSTVXZ" + + def license_plate_motorbike(self) -> str: + """Generate a license plate for motorbikes.""" + return self.bothify(self.random_element(self.license_formats_motorbike), + letters=string.ascii_uppercase) + + def license_plate_car(self) -> str: + """Generate a license plate for cars.""" + # Replace % with license_plate_prefix_letters + temp = re.sub(r"\%", + self.random_element(self.license_plate_prefix_letters), + self.random_element(self.license_formats)) + + # Replace @ with license_plate_prefix_letters_format_8 + temp = re.sub(r"\@", + self.random_element(self.license_plate_prefix_letters_format_8), + temp) + + return self.bothify(temp, letters=string.ascii_uppercase) + + def license_plate(self) -> str: + """Generate a license plate. + This method randomly chooses 10% between |license_plate_motorbike| + or 90% |license_plate_car| to generate the result. + """ + if self.generator.random.random() < 0.1: + return self.license_plate_motorbike() + return self.license_plate_car() diff --git a/tests/providers/test_automotive.py b/tests/providers/test_automotive.py index bda4b6268a..083ddf268f 100644 --- a/tests/providers/test_automotive.py +++ b/tests/providers/test_automotive.py @@ -217,3 +217,35 @@ class TestElGr(_SimpleAutomotiveTestMixin): """Test el_GR automotive provider methods""" license_plate_pattern = re.compile(r'^(?P[A-Z]{2,3}) \d{4}$') + + +class TestNlNl(_SimpleAutomotiveTestMixin): + """Test nl_NL automotive provider methods""" + license_plate_car_pattern = re.compile( + r'\d{2}-[BDFGHJKLNPRSTVXZ][A-Z]-[A-Z]{2}|' + r'\d{2}-[BDFGHJKLNPRSTVXZ][A-Z]{2}-\d|' + r'\d-[KSTVXZ][A-Z]{2}-\d{2}|' + r'[BDFGHJKLNPRSTVXZ][A-Z]-\d{3}-[A-Z]|' + r'[BDFGHJKLNPRSTVXZ]-\d{3}-[A-Z]{2}', + ) + + license_plate_motorbike_pattern = re.compile( + r'M[A-Z]-[A-Z]{2}-\d{2}|' + r'\d{2}-M[A-Z]-[A-Z]{2}', + ) + + license_plate_pattern = re.compile( + license_plate_car_pattern.pattern + '|' + license_plate_motorbike_pattern.pattern, + ) + + def test_plate_car(self, faker, num_samples): + for _ in range(num_samples): + plate = faker.license_plate_car() + assert isinstance(plate, str) + assert self.license_plate_car_pattern.match(plate) + + def test_plate_motorbike(self, faker, num_samples): + for _ in range(num_samples): + plate = faker.license_plate_motorbike() + assert isinstance(plate, str) + assert self.license_plate_motorbike_pattern.match(plate)