Repository: joke2k/faker

Issue:
Unicity and localization
* Faker version: 17.4.0
* OS: Archlinux

It seems that uniqueness and localization cannot be used together:

```python
>>> from faker import Faker
... fake = Faker(['it_IT', 'en_US', 'ja_JP'])
>>> fake['it_IT'].name()
'Giuseppina Juvara'
>>> fake['it_IT'].unique.name()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Generator' object has no attribute 'unique'

>>> fake.unique.name()
'石井 翔太'
>>> fake.unique['it_IT'].name()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'UniqueProxy' object is not subscriptable
```

I would lo to be able to use both features at the same time!




Discussion:
This issue is stale because it has been open for 30 days with no activity.
Please stale bot, let this ticket open.
This issue is stale because it has been open for 30 days with no activity.
This issue is still relevant.
This issue is stale because it has been open for 30 days with no activity.
I still don't agree 😮‍💨
Feel free to propose a corresponding PR.

Resolving patch:
diff --git a/faker/proxy.py b/faker/proxy.py
--- a/faker/proxy.py
+++ b/faker/proxy.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import copy
 import functools
 import re
@@ -35,7 +37,7 @@ def __init__(
         use_weighting: bool = True,
         **config: Any,
     ) -> None:
-        self._factory_map = OrderedDict()
+        self._factory_map: OrderedDict[str, Generator | Faker] = OrderedDict()
         self._weights = None
         self._unique_proxy = UniqueProxy(self)
         self._optional_proxy = OptionalProxy(self)
@@ -54,7 +56,7 @@ def __init__(
                 if final_locale not in locales:
                     locales.append(final_locale)
 
-        elif isinstance(locale, OrderedDict):
+        elif isinstance(locale, (OrderedDict, dict)):
             assert all(isinstance(v, (int, float)) for v in locale.values())
             odict = OrderedDict()
             for k, v in locale.items():
@@ -66,15 +68,25 @@ def __init__(
         else:
             locales = [DEFAULT_LOCALE]
 
-        for locale in locales:
-            self._factory_map[locale] = Factory.create(
-                locale,
+        if len(locales) == 1:
+            self._factory_map[locales[0]] = Factory.create(
+                locales[0],
                 providers,
                 generator,
                 includes,
                 use_weighting=use_weighting,
                 **config,
             )
+        else:
+            for locale in locales:
+                self._factory_map[locale] = Faker(
+                    locale,
+                    providers,
+                    generator,
+                    includes,
+                    use_weighting=use_weighting,
+                    **config,
+                )
 
         self._locales = locales
         self._factories = list(self._factory_map.values())
@@ -85,8 +97,12 @@ def __dir__(self):
             attributes |= {attr for attr in dir(factory) if not attr.startswith("_")}
         return sorted(attributes)
 
-    def __getitem__(self, locale: str) -> Generator:
-        return self._factory_map[locale.replace("-", "_")]
+    def __getitem__(self, locale: str) -> Faker:
+        if locale.replace("-", "_") in self.locales and len(self.locales) == 1:
+            return self
+        instance = self._factory_map[locale.replace("-", "_")]
+        assert isinstance(instance, Faker)  # for mypy
+        return instance
 
     def __getattribute__(self, attr: str) -> Any:
         """
@@ -273,10 +289,10 @@ def weights(self) -> Optional[List[Union[int, float]]]:
         return self._weights
 
     @property
-    def factories(self) -> List[Generator]:
+    def factories(self) -> List[Generator | Faker]:
         return self._factories
 
-    def items(self) -> List[Tuple[str, Generator]]:
+    def items(self) -> List[Tuple[str, Generator | Faker]]:
         return list(self._factory_map.items())
 
 


Test patch:
diff --git a/tests/providers/test_misc.py b/tests/providers/test_misc.py
--- a/tests/providers/test_misc.py
+++ b/tests/providers/test_misc.py
@@ -423,7 +423,7 @@ def test_dsv_with_row_ids(self, faker, num_samples):
     def test_dsv_data_columns(self, faker):
         num_rows = 10
         data_columns = ["{{name}}", "#??-####", "{{address}}", "{{phone_number}}"]
-        with patch.object(faker["en_US"], "pystr_format") as mock_pystr_format:
+        with patch.object(faker["en_US"].factories[0], "pystr_format") as mock_pystr_format:
             mock_pystr_format.assert_not_called()
             faker.dsv(data_columns=data_columns, num_rows=num_rows)
 
diff --git a/tests/providers/test_python.py b/tests/providers/test_python.py
--- a/tests/providers/test_python.py
+++ b/tests/providers/test_python.py
@@ -523,7 +523,7 @@ def setUp(self):
         Faker.seed(0)
 
     def test_formatter_invocation(self):
-        with patch.object(self.fake["en_US"], "foo") as mock_foo:
+        with patch.object(self.fake["en_US"].factories[0], "foo") as mock_foo:
             with patch("faker.providers.BaseProvider.bothify", wraps=self.fake.bothify) as mock_bothify:
                 mock_foo.return_value = "barbar"
                 value = self.fake.pystr_format("{{foo}}?#?{{foo}}?#?{{foo}}", letters="abcde")
diff --git a/tests/test_proxy.py b/tests/test_proxy.py
--- a/tests/test_proxy.py
+++ b/tests/test_proxy.py
@@ -103,14 +103,14 @@ def test_items(self):
         fake = Faker(locale)
         for locale_name, factory in fake.items():
             assert locale_name in processed_locale
-            assert isinstance(factory, Generator)
+            assert isinstance(factory, (Generator, Faker))
 
     def test_dunder_getitem(self):
         locale = ["de_DE", "en-US", "en-PH", "ja_JP"]
         fake = Faker(locale)
 
         for code in locale:
-            assert isinstance(fake[code], Generator)
+            assert isinstance(fake[code], (Generator, Faker))
 
         with pytest.raises(KeyError):
             fake["en_GB"]