We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Feature: Elector code for es_MX ssn provider
* Faker version: 18.11.2
* OS: NA

The National Electoral Institute in Mexico issues a unique identifier code for electors, it would be great if the library could fake those.

### Steps to reproduce

NA

### Expected behavior

```python
>>> fake.elector_code()
"GLVLMR80070509M900"
```

### Actual behavior

It's not implemented 😅 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `faker/providers/ssn/es_MX/__init__.py`
Content:
```
1 """
2 SSN provider for es_MX.
3 
4 This module adds a provider for mexican SSN, along with Unique Population
5 Registry Code (CURP) and Federal Taxpayer Registry ID (RFC).
6 """
7 
8 import random
9 import string
10 
11 from .. import Provider as BaseProvider
12 
13 ALPHABET = string.ascii_uppercase
14 ALPHANUMERIC = string.digits + ALPHABET
15 VOWELS = "AEIOU"
16 CONSONANTS = [letter for letter in ALPHABET if letter not in VOWELS]
17 
18 # https://es.wikipedia.org/wiki/Plantilla:Abreviaciones_de_los_estados_de_M%C3%A9xico
19 STATES_RENAPO = [
20     "AS",
21     "BC",
22     "BS",
23     "CC",
24     "CS",
25     "CH",
26     "DF",
27     "CL",
28     "CM",
29     "DG",
30     "GT",
31     "GR",
32     "HG",
33     "JC",
34     "MC",
35     "MN",
36     "MS",
37     "NT",
38     "NL",
39     "OC",
40     "PL",
41     "QO",
42     "QR",
43     "SP",
44     "SL",
45     "SR",
46     "TC",
47     "TS",
48     "TL",
49     "VZ",
50     "YN",
51     "ZS",
52     "NE",  # Foreign Born
53 ]
54 
55 FORBIDDEN_WORDS = {
56     "BUEI": "BUEX",
57     "BUEY": "BUEX",
58     "CACA": "CACX",
59     "CACO": "CACX",
60     "CAGA": "CAGX",
61     "CAGO": "CAGX",
62     "CAKA": "CAKX",
63     "CAKO": "CAKX",
64     "COGE": "COGX",
65     "COJA": "COJX",
66     "COJE": "COJX",
67     "COJI": "COJX",
68     "COJO": "COJX",
69     "CULO": "CULX",
70     "FETO": "FETX",
71     "GUEY": "GUEX",
72     "JOTO": "JOTX",
73     "KACA": "KACX",
74     "KACO": "KACX",
75     "KAGA": "KAGX",
76     "KAGO": "KAGX",
77     "KOGE": "KOGX",
78     "KOJO": "KOJX",
79     "KAKA": "KAKX",
80     "KULO": "KULX",
81     "MAME": "MAMX",
82     "MAMO": "MAMX",
83     "MEAR": "MEAX",
84     "MEAS": "MEAX",
85     "MEON": "MEOX",
86     "MION": "MIOX",
87     "MOCO": "MOCX",
88     "MULA": "MULX",
89     "PEDA": "PEDX",
90     "PEDO": "PEDX",
91     "PENE": "PENX",
92     "PUTA": "PUTX",
93     "PUTO": "PUTX",
94     "QULO": "QULX",
95     "RATA": "RATX",
96     "RUIN": "RUIN",
97 }
98 
99 CURP_CHARACTERS = "0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"
100 
101 
102 def _reduce_digits(number: int) -> int:
103     """
104     Sum of digits of a number until sum becomes single digit.
105 
106     Example:
107         658 => 6 + 5 + 8 = 19 => 1 + 9 = 10 => 1
108     """
109     if number == 0:
110         return 0
111     if number % 9 == 0:
112         return 9
113 
114     return number % 9
115 
116 
117 def ssn_checksum(digits: map) -> int:
118     """
119     Calculate the checksum for the mexican SSN (IMSS).
120     """
121     return -sum(_reduce_digits(n * (i % 2 + 1)) for i, n in enumerate(digits)) % 10
122 
123 
124 def curp_checksum(characters: str) -> int:
125     """
126     Calculate the checksum for the mexican CURP.
127     """
128     start = 18
129     return -sum((start - i) * CURP_CHARACTERS.index(n) for i, n in enumerate(characters)) % 10
130 
131 
132 class Provider(BaseProvider):
133     """
134     A Faker provider for the Mexican SSN, RFC and CURP
135     """
136 
137     ssn_formats = ("###########",)
138 
139     def ssn(self) -> str:
140         """
141         Mexican Social Security Number, as given by IMSS.
142 
143         :return: a random Mexican SSN
144         """
145         office = self.random_int(min=1, max=99)
146         birth_year = self.random_int(min=0, max=99)
147         start_year = self.random_int(min=0, max=99)
148         serial = self.random_int(min=1, max=9999)
149 
150         num = f"{office:02d}{start_year:02d}{birth_year:02d}{serial:04d}"
151 
152         check = ssn_checksum(map(int, num))
153         num += str(check)
154 
155         return num
156 
157     def curp(self) -> str:
158         """
159         See https://es.wikipedia.org/wiki/Clave_%C3%9Anica_de_Registro_de_Poblaci%C3%B3n.
160 
161         :return: a random Mexican CURP (Unique Population Registry Code)
162         """
163         birthday = self.generator.date_of_birth()
164 
165         first_surname = random.choice(ALPHABET) + random.choice(VOWELS)
166         second_surname = random.choice(ALPHABET)
167         given_name = random.choice(ALPHABET)
168         name_initials = first_surname + second_surname + given_name
169 
170         birth_date = birthday.strftime("%y%m%d")
171         gender = random.choice("HM")
172         state = random.choice(STATES_RENAPO)
173         first_surname_inside = random.choice(CONSONANTS)
174         second_surname_inside = random.choice(CONSONANTS)
175         given_name_inside = random.choice(ALPHABET)
176 
177         # This character is assigned to avoid duplicity
178         # It's normally '0' for those born < 2000
179         # and 'A' for those born >= 2000
180         assigned_character = "0" if birthday.year < 2000 else "A"
181 
182         name_initials = FORBIDDEN_WORDS.get(name_initials, name_initials)
183 
184         random_curp = (
185             name_initials
186             + birth_date
187             + gender
188             + state
189             + first_surname_inside
190             + second_surname_inside
191             + given_name_inside
192             + assigned_character
193         )
194 
195         random_curp += str(curp_checksum(random_curp))
196 
197         return random_curp
198 
199     def rfc(self, natural: bool = True) -> str:
200         """
201         See https://es.wikipedia.org/wiki/Registro_Federal_de_Contribuyentes
202 
203         :param natural: Whether to return the RFC of a natural person.
204             Otherwise return the RFC of a legal person.
205         :type natural: bool
206         :return: a random Mexican RFC
207         """
208         birthday = self.generator.date_of_birth()
209 
210         if natural:
211             first_surname = random.choice(ALPHABET) + random.choice(VOWELS)
212             second_surname = random.choice(ALPHABET)
213             given_name = random.choice(ALPHABET)
214             name_initials = first_surname + second_surname + given_name
215             name_initials = FORBIDDEN_WORDS.get(name_initials, name_initials)
216         else:
217             name_initials = (
218                 self.random_uppercase_letter() + self.random_uppercase_letter() + self.random_uppercase_letter()
219             )
220 
221         birth_date = birthday.strftime("%y%m%d")
222         disambiguation_code = random.choice(ALPHANUMERIC) + random.choice(ALPHANUMERIC) + random.choice(ALPHANUMERIC)
223 
224         random_rfc = name_initials + birth_date + disambiguation_code
225 
226         return random_rfc
227
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/faker/providers/ssn/es_MX/__init__.py b/faker/providers/ssn/es_MX/__init__.py
--- a/faker/providers/ssn/es_MX/__init__.py
+++ b/faker/providers/ssn/es_MX/__init__.py
@@ -7,9 +7,16 @@
 
 import random
 import string
+from typing import Optional
 
 from .. import Provider as BaseProvider
 
+try:
+    from typing import Literal  # type: ignore
+except ImportError:
+    from typing_extensions import Literal  # type: ignore
+
+
 ALPHABET = string.ascii_uppercase
 ALPHANUMERIC = string.digits + ALPHABET
 VOWELS = "AEIOU"
@@ -224,3 +231,30 @@
         random_rfc = name_initials + birth_date + disambiguation_code
 
         return random_rfc
+
+    def elector_code(self, gender: Literal["H", "M"] = None) -> str:
+        """
+        Unique elector code issued by INE (Instituto Nacional Electoral) in Mexico.
+
+        :param gender: Gender for which to generate the code. Will be randomly
+            selected if not provided.
+        :type gender: str
+        :return: a random INE elector code
+
+        :sample:
+        :sample: gender='M'
+        """
+        if gender and gender not in ("H", "M"):
+            raise ValueError("Gender must be 'H' or 'M'")
+
+        gender = gender or random.choice("HM")
+
+        consonants = "".join(random.choices(CONSONANTS, k=6))
+
+        birthday = self.generator.date_of_birth()
+        birth_date = birthday.strftime("%y%m%d")
+
+        entity = random.randint(1, 33)
+        disambiguation_code = "".join(random.choices(string.digits, k=3))
+
+        return f"{consonants}{birth_date}{entity:02d}{gender}{disambiguation_code}"

{"golden_diff": "diff --git a/faker/providers/ssn/es_MX/__init__.py b/faker/providers/ssn/es_MX/__init__.py\n--- a/faker/providers/ssn/es_MX/__init__.py\n+++ b/faker/providers/ssn/es_MX/__init__.py\n@@ -7,9 +7,16 @@\n \n import random\n import string\n+from typing import Optional\n \n from .. import Provider as BaseProvider\n \n+try:\n+    from typing import Literal  # type: ignore\n+except ImportError:\n+    from typing_extensions import Literal  # type: ignore\n+\n+\n ALPHABET = string.ascii_uppercase\n ALPHANUMERIC = string.digits + ALPHABET\n VOWELS = \"AEIOU\"\n@@ -224,3 +231,30 @@\n         random_rfc = name_initials + birth_date + disambiguation_code\n \n         return random_rfc\n+\n+    def elector_code(self, gender: Literal[\"H\", \"M\"] = None) -> str:\n+        \"\"\"\n+        Unique elector code issued by INE (Instituto Nacional Electoral) in Mexico.\n+\n+        :param gender: Gender for which to generate the code. Will be randomly\n+            selected if not provided.\n+        :type gender: str\n+        :return: a random INE elector code\n+\n+        :sample:\n+        :sample: gender='M'\n+        \"\"\"\n+        if gender and gender not in (\"H\", \"M\"):\n+            raise ValueError(\"Gender must be 'H' or 'M'\")\n+\n+        gender = gender or random.choice(\"HM\")\n+\n+        consonants = \"\".join(random.choices(CONSONANTS, k=6))\n+\n+        birthday = self.generator.date_of_birth()\n+        birth_date = birthday.strftime(\"%y%m%d\")\n+\n+        entity = random.randint(1, 33)\n+        disambiguation_code = \"\".join(random.choices(string.digits, k=3))\n+\n+        return f\"{consonants}{birth_date}{entity:02d}{gender}{disambiguation_code}\"\n", "issue": "Feature: Elector code for es_MX ssn provider\n* Faker version: 18.11.2\r\n* OS: NA\r\n\r\nThe National Electoral Institute in Mexico issues a unique identifier code for electors, it would be great if the library could fake those.\r\n\r\n### Steps to reproduce\r\n\r\nNA\r\n\r\n### Expected behavior\r\n\r\n```python\r\n>>> fake.elector_code()\r\n\"GLVLMR80070509M900\"\r\n```\r\n\r\n### Actual behavior\r\n\r\nIt's not implemented \ud83d\ude05 \r\n\n", "before_files": [{"content": "\"\"\"\nSSN provider for es_MX.\n\nThis module adds a provider for mexican SSN, along with Unique Population\nRegistry Code (CURP) and Federal Taxpayer Registry ID (RFC).\n\"\"\"\n\nimport random\nimport string\n\nfrom .. import Provider as BaseProvider\n\nALPHABET = string.ascii_uppercase\nALPHANUMERIC = string.digits + ALPHABET\nVOWELS = \"AEIOU\"\nCONSONANTS = [letter for letter in ALPHABET if letter not in VOWELS]\n\n# https://es.wikipedia.org/wiki/Plantilla:Abreviaciones_de_los_estados_de_M%C3%A9xico\nSTATES_RENAPO = [\n    \"AS\",\n    \"BC\",\n    \"BS\",\n    \"CC\",\n    \"CS\",\n    \"CH\",\n    \"DF\",\n    \"CL\",\n    \"CM\",\n    \"DG\",\n    \"GT\",\n    \"GR\",\n    \"HG\",\n    \"JC\",\n    \"MC\",\n    \"MN\",\n    \"MS\",\n    \"NT\",\n    \"NL\",\n    \"OC\",\n    \"PL\",\n    \"QO\",\n    \"QR\",\n    \"SP\",\n    \"SL\",\n    \"SR\",\n    \"TC\",\n    \"TS\",\n    \"TL\",\n    \"VZ\",\n    \"YN\",\n    \"ZS\",\n    \"NE\",  # Foreign Born\n]\n\nFORBIDDEN_WORDS = {\n    \"BUEI\": \"BUEX\",\n    \"BUEY\": \"BUEX\",\n    \"CACA\": \"CACX\",\n    \"CACO\": \"CACX\",\n    \"CAGA\": \"CAGX\",\n    \"CAGO\": \"CAGX\",\n    \"CAKA\": \"CAKX\",\n    \"CAKO\": \"CAKX\",\n    \"COGE\": \"COGX\",\n    \"COJA\": \"COJX\",\n    \"COJE\": \"COJX\",\n    \"COJI\": \"COJX\",\n    \"COJO\": \"COJX\",\n    \"CULO\": \"CULX\",\n    \"FETO\": \"FETX\",\n    \"GUEY\": \"GUEX\",\n    \"JOTO\": \"JOTX\",\n    \"KACA\": \"KACX\",\n    \"KACO\": \"KACX\",\n    \"KAGA\": \"KAGX\",\n    \"KAGO\": \"KAGX\",\n    \"KOGE\": \"KOGX\",\n    \"KOJO\": \"KOJX\",\n    \"KAKA\": \"KAKX\",\n    \"KULO\": \"KULX\",\n    \"MAME\": \"MAMX\",\n    \"MAMO\": \"MAMX\",\n    \"MEAR\": \"MEAX\",\n    \"MEAS\": \"MEAX\",\n    \"MEON\": \"MEOX\",\n    \"MION\": \"MIOX\",\n    \"MOCO\": \"MOCX\",\n    \"MULA\": \"MULX\",\n    \"PEDA\": \"PEDX\",\n    \"PEDO\": \"PEDX\",\n    \"PENE\": \"PENX\",\n    \"PUTA\": \"PUTX\",\n    \"PUTO\": \"PUTX\",\n    \"QULO\": \"QULX\",\n    \"RATA\": \"RATX\",\n    \"RUIN\": \"RUIN\",\n}\n\nCURP_CHARACTERS = \"0123456789ABCDEFGHIJKLMN\u00d1OPQRSTUVWXYZ\"\n\n\ndef _reduce_digits(number: int) -> int:\n    \"\"\"\n    Sum of digits of a number until sum becomes single digit.\n\n    Example:\n        658 => 6 + 5 + 8 = 19 => 1 + 9 = 10 => 1\n    \"\"\"\n    if number == 0:\n        return 0\n    if number % 9 == 0:\n        return 9\n\n    return number % 9\n\n\ndef ssn_checksum(digits: map) -> int:\n    \"\"\"\n    Calculate the checksum for the mexican SSN (IMSS).\n    \"\"\"\n    return -sum(_reduce_digits(n * (i % 2 + 1)) for i, n in enumerate(digits)) % 10\n\n\ndef curp_checksum(characters: str) -> int:\n    \"\"\"\n    Calculate the checksum for the mexican CURP.\n    \"\"\"\n    start = 18\n    return -sum((start - i) * CURP_CHARACTERS.index(n) for i, n in enumerate(characters)) % 10\n\n\nclass Provider(BaseProvider):\n    \"\"\"\n    A Faker provider for the Mexican SSN, RFC and CURP\n    \"\"\"\n\n    ssn_formats = (\"###########\",)\n\n    def ssn(self) -> str:\n        \"\"\"\n        Mexican Social Security Number, as given by IMSS.\n\n        :return: a random Mexican SSN\n        \"\"\"\n        office = self.random_int(min=1, max=99)\n        birth_year = self.random_int(min=0, max=99)\n        start_year = self.random_int(min=0, max=99)\n        serial = self.random_int(min=1, max=9999)\n\n        num = f\"{office:02d}{start_year:02d}{birth_year:02d}{serial:04d}\"\n\n        check = ssn_checksum(map(int, num))\n        num += str(check)\n\n        return num\n\n    def curp(self) -> str:\n        \"\"\"\n        See https://es.wikipedia.org/wiki/Clave_%C3%9Anica_de_Registro_de_Poblaci%C3%B3n.\n\n        :return: a random Mexican CURP (Unique Population Registry Code)\n        \"\"\"\n        birthday = self.generator.date_of_birth()\n\n        first_surname = random.choice(ALPHABET) + random.choice(VOWELS)\n        second_surname = random.choice(ALPHABET)\n        given_name = random.choice(ALPHABET)\n        name_initials = first_surname + second_surname + given_name\n\n        birth_date = birthday.strftime(\"%y%m%d\")\n        gender = random.choice(\"HM\")\n        state = random.choice(STATES_RENAPO)\n        first_surname_inside = random.choice(CONSONANTS)\n        second_surname_inside = random.choice(CONSONANTS)\n        given_name_inside = random.choice(ALPHABET)\n\n        # This character is assigned to avoid duplicity\n        # It's normally '0' for those born < 2000\n        # and 'A' for those born >= 2000\n        assigned_character = \"0\" if birthday.year < 2000 else \"A\"\n\n        name_initials = FORBIDDEN_WORDS.get(name_initials, name_initials)\n\n        random_curp = (\n            name_initials\n            + birth_date\n            + gender\n            + state\n            + first_surname_inside\n            + second_surname_inside\n            + given_name_inside\n            + assigned_character\n        )\n\n        random_curp += str(curp_checksum(random_curp))\n\n        return random_curp\n\n    def rfc(self, natural: bool = True) -> str:\n        \"\"\"\n        See https://es.wikipedia.org/wiki/Registro_Federal_de_Contribuyentes\n\n        :param natural: Whether to return the RFC of a natural person.\n            Otherwise return the RFC of a legal person.\n        :type natural: bool\n        :return: a random Mexican RFC\n        \"\"\"\n        birthday = self.generator.date_of_birth()\n\n        if natural:\n            first_surname = random.choice(ALPHABET) + random.choice(VOWELS)\n            second_surname = random.choice(ALPHABET)\n            given_name = random.choice(ALPHABET)\n            name_initials = first_surname + second_surname + given_name\n            name_initials = FORBIDDEN_WORDS.get(name_initials, name_initials)\n        else:\n            name_initials = (\n                self.random_uppercase_letter() + self.random_uppercase_letter() + self.random_uppercase_letter()\n            )\n\n        birth_date = birthday.strftime(\"%y%m%d\")\n        disambiguation_code = random.choice(ALPHANUMERIC) + random.choice(ALPHANUMERIC) + random.choice(ALPHANUMERIC)\n\n        random_rfc = name_initials + birth_date + disambiguation_code\n\n        return random_rfc\n", "path": "faker/providers/ssn/es_MX/__init__.py"}], "after_files": [{"content": "\"\"\"\nSSN provider for es_MX.\n\nThis module adds a provider for mexican SSN, along with Unique Population\nRegistry Code (CURP) and Federal Taxpayer Registry ID (RFC).\n\"\"\"\n\nimport random\nimport string\nfrom typing import Optional\n\nfrom .. import Provider as BaseProvider\n\ntry:\n    from typing import Literal  # type: ignore\nexcept ImportError:\n    from typing_extensions import Literal  # type: ignore\n\n\nALPHABET = string.ascii_uppercase\nALPHANUMERIC = string.digits + ALPHABET\nVOWELS = \"AEIOU\"\nCONSONANTS = [letter for letter in ALPHABET if letter not in VOWELS]\n\n# https://es.wikipedia.org/wiki/Plantilla:Abreviaciones_de_los_estados_de_M%C3%A9xico\nSTATES_RENAPO = [\n    \"AS\",\n    \"BC\",\n    \"BS\",\n    \"CC\",\n    \"CS\",\n    \"CH\",\n    \"DF\",\n    \"CL\",\n    \"CM\",\n    \"DG\",\n    \"GT\",\n    \"GR\",\n    \"HG\",\n    \"JC\",\n    \"MC\",\n    \"MN\",\n    \"MS\",\n    \"NT\",\n    \"NL\",\n    \"OC\",\n    \"PL\",\n    \"QO\",\n    \"QR\",\n    \"SP\",\n    \"SL\",\n    \"SR\",\n    \"TC\",\n    \"TS\",\n    \"TL\",\n    \"VZ\",\n    \"YN\",\n    \"ZS\",\n    \"NE\",  # Foreign Born\n]\n\nFORBIDDEN_WORDS = {\n    \"BUEI\": \"BUEX\",\n    \"BUEY\": \"BUEX\",\n    \"CACA\": \"CACX\",\n    \"CACO\": \"CACX\",\n    \"CAGA\": \"CAGX\",\n    \"CAGO\": \"CAGX\",\n    \"CAKA\": \"CAKX\",\n    \"CAKO\": \"CAKX\",\n    \"COGE\": \"COGX\",\n    \"COJA\": \"COJX\",\n    \"COJE\": \"COJX\",\n    \"COJI\": \"COJX\",\n    \"COJO\": \"COJX\",\n    \"CULO\": \"CULX\",\n    \"FETO\": \"FETX\",\n    \"GUEY\": \"GUEX\",\n    \"JOTO\": \"JOTX\",\n    \"KACA\": \"KACX\",\n    \"KACO\": \"KACX\",\n    \"KAGA\": \"KAGX\",\n    \"KAGO\": \"KAGX\",\n    \"KOGE\": \"KOGX\",\n    \"KOJO\": \"KOJX\",\n    \"KAKA\": \"KAKX\",\n    \"KULO\": \"KULX\",\n    \"MAME\": \"MAMX\",\n    \"MAMO\": \"MAMX\",\n    \"MEAR\": \"MEAX\",\n    \"MEAS\": \"MEAX\",\n    \"MEON\": \"MEOX\",\n    \"MION\": \"MIOX\",\n    \"MOCO\": \"MOCX\",\n    \"MULA\": \"MULX\",\n    \"PEDA\": \"PEDX\",\n    \"PEDO\": \"PEDX\",\n    \"PENE\": \"PENX\",\n    \"PUTA\": \"PUTX\",\n    \"PUTO\": \"PUTX\",\n    \"QULO\": \"QULX\",\n    \"RATA\": \"RATX\",\n    \"RUIN\": \"RUIN\",\n}\n\nCURP_CHARACTERS = \"0123456789ABCDEFGHIJKLMN\u00d1OPQRSTUVWXYZ\"\n\n\ndef _reduce_digits(number: int) -> int:\n    \"\"\"\n    Sum of digits of a number until sum becomes single digit.\n\n    Example:\n        658 => 6 + 5 + 8 = 19 => 1 + 9 = 10 => 1\n    \"\"\"\n    if number == 0:\n        return 0\n    if number % 9 == 0:\n        return 9\n\n    return number % 9\n\n\ndef ssn_checksum(digits: map) -> int:\n    \"\"\"\n    Calculate the checksum for the mexican SSN (IMSS).\n    \"\"\"\n    return -sum(_reduce_digits(n * (i % 2 + 1)) for i, n in enumerate(digits)) % 10\n\n\ndef curp_checksum(characters: str) -> int:\n    \"\"\"\n    Calculate the checksum for the mexican CURP.\n    \"\"\"\n    start = 18\n    return -sum((start - i) * CURP_CHARACTERS.index(n) for i, n in enumerate(characters)) % 10\n\n\nclass Provider(BaseProvider):\n    \"\"\"\n    A Faker provider for the Mexican SSN, RFC and CURP\n    \"\"\"\n\n    ssn_formats = (\"###########\",)\n\n    def ssn(self) -> str:\n        \"\"\"\n        Mexican Social Security Number, as given by IMSS.\n\n        :return: a random Mexican SSN\n        \"\"\"\n        office = self.random_int(min=1, max=99)\n        birth_year = self.random_int(min=0, max=99)\n        start_year = self.random_int(min=0, max=99)\n        serial = self.random_int(min=1, max=9999)\n\n        num = f\"{office:02d}{start_year:02d}{birth_year:02d}{serial:04d}\"\n\n        check = ssn_checksum(map(int, num))\n        num += str(check)\n\n        return num\n\n    def curp(self) -> str:\n        \"\"\"\n        See https://es.wikipedia.org/wiki/Clave_%C3%9Anica_de_Registro_de_Poblaci%C3%B3n.\n\n        :return: a random Mexican CURP (Unique Population Registry Code)\n        \"\"\"\n        birthday = self.generator.date_of_birth()\n\n        first_surname = random.choice(ALPHABET) + random.choice(VOWELS)\n        second_surname = random.choice(ALPHABET)\n        given_name = random.choice(ALPHABET)\n        name_initials = first_surname + second_surname + given_name\n\n        birth_date = birthday.strftime(\"%y%m%d\")\n        gender = random.choice(\"HM\")\n        state = random.choice(STATES_RENAPO)\n        first_surname_inside = random.choice(CONSONANTS)\n        second_surname_inside = random.choice(CONSONANTS)\n        given_name_inside = random.choice(ALPHABET)\n\n        # This character is assigned to avoid duplicity\n        # It's normally '0' for those born < 2000\n        # and 'A' for those born >= 2000\n        assigned_character = \"0\" if birthday.year < 2000 else \"A\"\n\n        name_initials = FORBIDDEN_WORDS.get(name_initials, name_initials)\n\n        random_curp = (\n            name_initials\n            + birth_date\n            + gender\n            + state\n            + first_surname_inside\n            + second_surname_inside\n            + given_name_inside\n            + assigned_character\n        )\n\n        random_curp += str(curp_checksum(random_curp))\n\n        return random_curp\n\n    def rfc(self, natural: bool = True) -> str:\n        \"\"\"\n        See https://es.wikipedia.org/wiki/Registro_Federal_de_Contribuyentes\n\n        :param natural: Whether to return the RFC of a natural person.\n            Otherwise return the RFC of a legal person.\n        :type natural: bool\n        :return: a random Mexican RFC\n        \"\"\"\n        birthday = self.generator.date_of_birth()\n\n        if natural:\n            first_surname = random.choice(ALPHABET) + random.choice(VOWELS)\n            second_surname = random.choice(ALPHABET)\n            given_name = random.choice(ALPHABET)\n            name_initials = first_surname + second_surname + given_name\n            name_initials = FORBIDDEN_WORDS.get(name_initials, name_initials)\n        else:\n            name_initials = (\n                self.random_uppercase_letter() + self.random_uppercase_letter() + self.random_uppercase_letter()\n            )\n\n        birth_date = birthday.strftime(\"%y%m%d\")\n        disambiguation_code = random.choice(ALPHANUMERIC) + random.choice(ALPHANUMERIC) + random.choice(ALPHANUMERIC)\n\n        random_rfc = name_initials + birth_date + disambiguation_code\n\n        return random_rfc\n\n    def elector_code(self, gender: Literal[\"H\", \"M\"] = None) -> str:\n        \"\"\"\n        Unique elector code issued by INE (Instituto Nacional Electoral) in Mexico.\n\n        :param gender: Gender for which to generate the code. Will be randomly\n            selected if not provided.\n        :type gender: str\n        :return: a random INE elector code\n\n        :sample:\n        :sample: gender='M'\n        \"\"\"\n        if gender and gender not in (\"H\", \"M\"):\n            raise ValueError(\"Gender must be 'H' or 'M'\")\n\n        gender = gender or random.choice(\"HM\")\n\n        consonants = \"\".join(random.choices(CONSONANTS, k=6))\n\n        birthday = self.generator.date_of_birth()\n        birth_date = birthday.strftime(\"%y%m%d\")\n\n        entity = random.randint(1, 33)\n        disambiguation_code = \"\".join(random.choices(string.digits, k=3))\n\n        return f\"{consonants}{birth_date}{entity:02d}{gender}{disambiguation_code}\"\n", "path": "faker/providers/ssn/es_MX/__init__.py"}]}