Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Suporte a anotações modernas `legal_process` [#622](https://github.com/brazilian-utils/brutils-python/pull/634)

### Fixed

- Suporte a anotações modernas `voter_id` [#623](https://github.com/brazilian-utils/brutils-python/pull/638)

## [2.3.0] - 2025-10-07

### Added
Expand Down
21 changes: 11 additions & 10 deletions brutils/voter_id.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from random import randint


def is_valid(voter_id): # type: (str) -> bool
def is_valid(voter_id: str) -> bool:
"""
Check if a Brazilian voter id number is valid.
It does not verify if the voter id actually exists.
Expand Down Expand Up @@ -50,7 +50,7 @@ def is_valid(voter_id): # type: (str) -> bool
return True


def _is_length_valid(voter_id): # type: (str) -> bool
def _is_length_valid(voter_id: str) -> bool:
"""
Check if the length of the provided voter id is valid.
Typically, the length should be 12, but there are cases for SP and MG where
Expand All @@ -73,7 +73,7 @@ def _is_length_valid(voter_id): # type: (str) -> bool
return len(voter_id) == 13 and federative_union in ["01", "02"]


def _get_sequential_number(voter_id): # type: (str) -> str
def _get_sequential_number(voter_id: str) -> str:
"""
Some voter ids in São Paulo and Minas Gerais may have nine digits in their
sequential number instead of eight. This fact does not compromise the
Expand All @@ -91,7 +91,7 @@ def _get_sequential_number(voter_id): # type: (str) -> str
return voter_id[:8]


def _get_federative_union(voter_id): # type: (str) -> str
def _get_federative_union(voter_id: str) -> str:
"""
Returns the two digits that represent the federative union for the given
voter id. Indexing it backwards, as the sequential_number can have eight
Expand All @@ -107,7 +107,7 @@ def _get_federative_union(voter_id): # type: (str) -> str
return voter_id[-4:-2]


def _get_verifying_digits(voter_id): # type: (str) -> str
def _get_verifying_digits(voter_id: str) -> str:
"""
Returns the two verifying digits for the given voter id. Indexing it
backwards, as the sequential_number can have eight or nine digits.
Expand All @@ -122,7 +122,7 @@ def _get_verifying_digits(voter_id): # type: (str) -> str
return voter_id[-2:]


def _is_federative_union_valid(federative_union): # type: (str) -> bool
def _is_federative_union_valid(federative_union: str) -> bool:
"""
Check if the federative union is valid.

Expand All @@ -137,7 +137,7 @@ def _is_federative_union_valid(federative_union): # type: (str) -> bool
return federative_union in ["{:02d}".format(i) for i in range(1, 29)]


def _calculate_vd1(sequential_number, federative_union): # type: (str, str) -> bool
def _calculate_vd1(sequential_number: str, federative_union: str) -> int:
"""
Calculate the first verifying digit.

Expand Down Expand Up @@ -178,7 +178,7 @@ def _calculate_vd1(sequential_number, federative_union): # type: (str, str) ->
return vd1


def _calculate_vd2(federative_union, vd1): # type: (str, int) -> str
def _calculate_vd2(federative_union: str, vd1: int) -> int:
"""
Calculate the second verifying digit.

Expand Down Expand Up @@ -214,7 +214,7 @@ def _calculate_vd2(federative_union, vd1): # type: (str, int) -> str
return vd2


def generate(federative_union="ZZ") -> str:
def generate(federative_union: str = "ZZ") -> str | None:
"""
Generates a random valid Brazilian voter registration.

Expand Down Expand Up @@ -263,9 +263,10 @@ def generate(federative_union="ZZ") -> str:
vd1 = _calculate_vd1(sequential_number, uf_number)
vd2 = _calculate_vd2(uf_number, vd1)
return f"{sequential_number}{uf_number}{vd1}{vd2}"
return None


def format_voter_id(voter_id): # type: (str) -> str
def format_voter_id(voter_id: str) -> str | None:
"""
Format a voter ID for display with visual spaces.

Expand Down
12 changes: 12 additions & 0 deletions tests/test_voter_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def test_valid_voter_id(self):
# test a valid voter id number
voter_id = "217633460930"
self.assertIs(is_valid(voter_id), True)
self.assertIsInstance(is_valid(voter_id), bool)

def test_invalid_voter_id(self):
# test an invalid voter id number (dv1 & UF fail)
Expand Down Expand Up @@ -59,12 +60,18 @@ def test_get_voter_id_parts(self):
verifying_digits = _get_verifying_digits(voter_id)

self.assertEqual(sequential_number, "12345678")
self.assertIsInstance(sequential_number, str)

self.assertEqual(federative_union, "AB")
self.assertIsInstance(federative_union, str)

self.assertEqual(verifying_digits, "12")
self.assertIsInstance(verifying_digits, str)

def test_valid_length_verify(self):
voter_id = "123456789012"
self.assertIs(_is_length_valid(voter_id), True)
self.assertIsInstance(_is_length_valid(voter_id), bool)

def test_invalid_length_verify(self):
voter_id = "12345678AB123" # Invalid length
Expand All @@ -79,6 +86,7 @@ def test_calculate_vd1(self):
self.assertIs(_calculate_vd1("42750359", "02"), 1)
# test edge case: rest is 10, declare vd1 as 0
self.assertIs(_calculate_vd1("73146415", "03"), 0)
self.assertIsInstance(_calculate_vd1("73146415", "03"), int)

def test_calculate_vd2(self):
self.assertIs(_calculate_vd2("02", 7), 2)
Expand All @@ -90,6 +98,7 @@ def test_calculate_vd2(self):
# edge case: if UF is "02" (for MG) and rest == 0
# declare dv2 as 1 instead
self.assertIs(_calculate_vd2("02", 8), 1)
self.assertIsInstance(_calculate_vd2("02", 8), int)

def test_generate_voter_id(self):
# test if is_valid a voter id from MG
Expand All @@ -103,13 +112,16 @@ def test_generate_voter_id(self):
# test if is_valid a voter id from foreigner
voter_id = generate()
self.assertIs(is_valid(voter_id), True)
self.assertIsInstance(voter_id, str)

# test if UF is not valid
voter_id = generate(federative_union="XX")
self.assertIs(is_valid(voter_id), False)
self.assertIsNone(voter_id)

def test_format_voter_id(self):
self.assertEqual(format_voter_id("277627122852"), "2776 2712 28 52")
self.assertIsInstance(format_voter_id("277627122852"), str)
self.assertIsNone(format_voter_id("00000000000"))
self.assertIsNone(format_voter_id("0000000000a"))
self.assertIsNone(format_voter_id("000000000000"))
Expand Down