Repository: joke2k/faker

Issue:
pyfloat produces values outside of the allowed range.
* Faker version: 17.6.0
* OS: Windows 10

Brief summary of the issue goes here.

`pyfloat` produces values outside of the allowed range.
It appears this is related to the fact that the provided `min_value` and `max_value` are overwritten see [line 150](https://github.com/joke2k/faker/blob/master/faker/providers/python/__init__.py#L150). So even the final check to see if the result exceeds the `max_value` will not catch these scenarios. 

### Steps to reproduce

```python
for i in range(10000):
    min_x, max_x = (-120.123, -115.321)
    min_y, max_y = (20.123, 30.321)
    x= fake.pyfloat(min_value=min_x, max_value=max_x)
    y= fake.pyfloat(min_value=min_y, max_value=max_y)
    if x < min_x:
        print(f'Exceeds min {x} < {min_x}')
    if x > max_x:
        print(f'Exceeds max {x} > {min_x}')
    if y < min_y:
        print(f'Exceeds min {y} < {min_y}')
    if y > max_y:
        print(f'Exceeds max {y} > {min_y}')
```

Partial output:
```
Exceeds max -115.0 > -115.321
Exceeds max -115.23 > -115.321
Exceeds max -115.1989873 > -115.321
Exceeds max -115.282293711644 > -115.321
Exceeds min 20.10361238 < 20.123
Exceeds max -115.127203600243 > -115.321
Exceeds max -115.1 > -115.321
Exceeds min 20.0 < 20.123
Exceeds max -115.19968337045 > -115.321
Exceeds max -115.198 > -115.321
Exceeds max -115.12414928 > -115.321
Exceeds min 20.0 < 20.123
```

### Expected behavior

Values should be bound by the `min_value` and `max_value`

### Actual behavior

Values are exceeding the allowed boundary


Discussion:

Patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index e4965c6b..50f353cd 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 17.6.0
+current_version = 18.3.3
 files = VERSION faker/__init__.py docs/conf.py
 commit = True
 tag = True
diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml
index 9ab12747..9dde6fff 100644
--- a/.github/workflows/issues.yml
+++ b/.github/workflows/issues.yml
@@ -10,7 +10,7 @@ jobs:
       issues: write
       pull-requests: write
     steps:
-      - uses: actions/stale@v7
+      - uses: actions/stale@v8
         with:
           days-before-issue-stale: 90
           days-before-issue-close: 14
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5919813..029d4239 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,39 @@
 ## Changelog
 
+### [v18.3.3 - 2023-04-04](https://github.com/joke2k/faker/compare/v18.3.2...v18.3.3)
+
+* Use correct union type for provider argument (#1840). Thanks @DanielSchaffer.
+
+### [v18.3.2 - 2023-04-01](https://github.com/joke2k/faker/compare/v18.3.1...v18.3.2)
+
+* Bump actions/stale from 7 to 8 (#1833). Thanks @dependabot[bot].
+
+### [v18.3.1 - 2023-03-23](https://github.com/joke2k/faker/compare/v18.3.0...v18.3.1)
+
+* Fix determinism in `state_abbr()` for `en_US`. Thanks @DavidCain.
+
+### [v18.3.0 - 2023-03-21](https://github.com/joke2k/faker/compare/v18.2.1...v18.3.0)
+
+* Separate freely-associated states & US territories. Thanks @DavidCain.
+
+### [v18.2.1 - 2023-03-21](https://github.com/joke2k/faker/compare/v18.2.0...v18.2.1)
+
+* Fix value error formatting. Thanks @dariocurr.
+
+### [v18.2.0 - 2023-03-20](https://github.com/joke2k/faker/compare/v18.1.0...v18.2.0)
+
+* Add `pyobject` generator. Thanks @dariocurr.
+
+### [v18.1.0 - 2023-03-20](https://github.com/joke2k/faker/compare/v18.0.0...v18.1.0)
+
+* Add lorem provider for `nl_BE`. Thanks @takis.
+* Add `nl_BE` automotive provider. Thanks @takis.
+* Add `nl_BE` company provider. Thanks @takis.
+
+### [v18.0.0 - 2023-03-20](https://github.com/joke2k/faker/compare/v17.6.0...v18.0.0)
+
+* Add territory zip codes for `en_US`. Thanks @johnekent.
+
 ### [v17.6.0 - 2023-03-03](https://github.com/joke2k/faker/compare/v17.5.0...v17.6.0)
 
 * Add `nl_BE` bank provider. Thanks @takis.
diff --git a/README.rst b/README.rst
index f796e635..9fa5472e 100644
--- a/README.rst
+++ b/README.rst
@@ -381,8 +381,8 @@ Seeding the Generator
 
 When using Faker for unit testing, you will often want to generate the same
 data set. For convenience, the generator also provide a ``seed()`` method,
-which seeds the shared random number generator. Calling the same methods with
-the same version of faker and seed produces the same results.
+which seeds the shared random number generator. Seed produces the same result
+when the same methods with the same version of faker are called.
 
 .. code:: python
 
diff --git a/VERSION b/VERSION
index ea3bf215..4fa79f16 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-17.6.0
+18.3.3
diff --git a/docs/conf.py b/docs/conf.py
index 8500e9a0..ea0fc359 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -51,9 +51,9 @@ copyright = "2014, Daniele Faraglia"
 # built documents.
 #
 # The short X.Y version.
-version = "17.6.0"
+version = "18.3.3"
 # The full version, including alpha/beta/rc tags.
-release = "17.6.0"
+release = "18.3.3"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/faker/__init__.py b/faker/__init__.py
index 0ac5d8bd..b94b096f 100644
--- a/faker/__init__.py
+++ b/faker/__init__.py
@@ -2,6 +2,6 @@ from faker.factory import Factory
 from faker.generator import Generator
 from faker.proxy import Faker
 
-VERSION = "17.6.0"
+VERSION = "18.3.3"
 
 __all__ = ("Factory", "Generator", "Faker")
diff --git a/faker/generator.py b/faker/generator.py
index 2e5dc250..b04c0636 100644
--- a/faker/generator.py
+++ b/faker/generator.py
@@ -1,7 +1,7 @@
 import random as random_module
 import re
 
-from typing import TYPE_CHECKING, Any, Callable, Dict, Hashable, List, Optional
+from typing import TYPE_CHECKING, Any, Callable, Dict, Hashable, List, Optional, Type, Union
 
 from .typing import SeedType
 
@@ -29,7 +29,7 @@ class Generator:
         self.__config = dict(list(self.__config.items()) + list(config.items()))
         self.__random = random
 
-    def add_provider(self, provider: "BaseProvider") -> None:
+    def add_provider(self, provider: Union["BaseProvider", Type["BaseProvider"]]) -> None:
         if isinstance(provider, type):
             provider = provider(self)
 
diff --git a/faker/providers/address/en_US/__init__.py b/faker/providers/address/en_US/__init__.py
index 4bf14695..dab1b468 100644
--- a/faker/providers/address/en_US/__init__.py
+++ b/faker/providers/address/en_US/__init__.py
@@ -1,5 +1,5 @@
 from collections import OrderedDict
-from typing import Optional
+from typing import Optional, Tuple
 
 from ..en import Provider as AddressProvider
 
@@ -419,7 +419,8 @@ class Provider(AddressProvider):
         "WV": (24701, 26886),
         "WI": (53001, 54990),
         "WY": (82001, 83128),
-        # Territories - incomplete ranges with accurate subsets - https://www.geonames.org/postalcode-search.html
+        # Territories & freely-associated states
+        # incomplete ranges with accurate subsets - https://www.geonames.org/postalcode-search.html
         "AS": (96799, 96799),
         "FM": (96941, 96944),
         "GU": (96910, 96932),
@@ -432,16 +433,21 @@ class Provider(AddressProvider):
 
     territories_abbr = (
         "AS",
-        "FM",
         "GU",
-        "MH",
         "MP",
-        "PW",
         "PR",
         "VI",
     )
 
-    states_and_territories_abbr = states_abbr + territories_abbr
+    # Freely-associated states (sovereign states; members of COFA)
+    # https://en.wikipedia.org/wiki/Compact_of_Free_Association
+    freely_associated_states_abbr = (
+        "FM",
+        "MH",
+        "PW",
+    )
+
+    known_usps_abbr = states_abbr + territories_abbr + freely_associated_states_abbr
 
     military_state_abbr = ("AE", "AA", "AP")
 
@@ -494,16 +500,28 @@ class Provider(AddressProvider):
 
     state = administrative_unit
 
-    def state_abbr(self, include_territories: bool = True) -> str:
+    def state_abbr(
+        self,
+        include_territories: bool = True,
+        include_freely_associated_states: bool = True,
+    ) -> str:
         """
-        :returns: A random state or territory abbreviation.
+        :returns: A random two-letter USPS postal code
+
+        By default, the resulting code may abbreviate any of the fity states,
+        five US territories, or three freely-associating sovereign states.
 
         :param include_territories: If True, territories will be included.
-            If False, only states will be returned.
+            If False, US territories will be excluded.
+        :param include_freely_associated_states: If True, freely-associated states will be included.
+            If False, sovereign states in free association with the US will be excluded.
         """
+        abbreviations: Tuple[str, ...] = self.states_abbr
         if include_territories:
-            return self.random_element(self.states_and_territories_abbr)
-        return self.random_element(self.states_abbr)
+            abbreviations += self.territories_abbr
+        if include_freely_associated_states:
+            abbreviations += self.freely_associated_states_abbr
+        return self.random_element(abbreviations)
 
     def postcode(self) -> str:
         return "%05d" % self.generator.random.randint(501, 99950)
@@ -520,7 +538,7 @@ class Provider(AddressProvider):
         if state_abbr is None:
             state_abbr = self.random_element(self.states_abbr)
 
-        if state_abbr in self.states_and_territories_abbr:
+        if state_abbr in self.known_usps_abbr:
             postcode = "%d" % (
                 self.generator.random.randint(
                     self.states_postcode[state_abbr][0],
diff --git a/faker/providers/automotive/nl_BE/__init__.py b/faker/providers/automotive/nl_BE/__init__.py
new file mode 100644
index 00000000..19f24cac
--- /dev/null
+++ b/faker/providers/automotive/nl_BE/__init__.py
@@ -0,0 +1,16 @@
+from .. import Provider as AutomotiveProvider
+
+
+class Provider(AutomotiveProvider):
+    """Implement automotive provider for `nl_BE` locale.
+
+    https://nl.wikipedia.org/wiki/Belgisch_kenteken
+    """
+
+    license_formats = (
+        "???-###",  # 1973-2008
+        "###-???",  # 2008-2010
+        # New formats after 2010
+        "1-???-###",
+        "2-???-###",
+    )
diff --git a/faker/providers/company/nl_BE/__init__.py b/faker/providers/company/nl_BE/__init__.py
new file mode 100644
index 00000000..30ac7f52
--- /dev/null
+++ b/faker/providers/company/nl_BE/__init__.py
@@ -0,0 +1,10 @@
+from .. import Provider as CompanyProvider
+
+
+class Provider(CompanyProvider):
+    formats = (
+        "{{last_name}} {{company_suffix}}",
+        "{{last_name}}-{{last_name}} {{company_suffix}}",
+        "{{last_name}}, {{last_name}} en {{last_name}} {{company_suffix}}",
+    )
+    company_suffixes = ("NV", "BV", "CV", "VOF", "CommV")
diff --git a/faker/providers/lorem/nl_BE/__init__.py b/faker/providers/lorem/nl_BE/__init__.py
new file mode 100644
index 00000000..efc33ef9
--- /dev/null
+++ b/faker/providers/lorem/nl_BE/__init__.py
@@ -0,0 +1,1015 @@
+from typing import Dict
+
+from .. import Provider as LoremProvider
+
+
+class Provider(LoremProvider):
+    """Implement lorem provider for ``nl_BE`` locale.
+
+    Source: https://nl.wiktionary.org/wiki/WikiWoordenboek:Lijst_met_1000_basiswoorden
+    """
+
+    word_list = (
+        "aan",
+        "aanbod",
+        "aanraken",
+        "aanval",
+        "aap",
+        "aardappel",
+        "aarde",
+        "aardig",
+        "acht",
+        "achter",
+        "actief",
+        "activiteit",
+        "ademen",
+        "af",
+        "afgelopen",
+        "afhangen",
+        "afmaken",
+        "afname",
+        "afspraak",
+        "afval",
+        "al",
+        "algemeen",
+        "alleen",
+        "alles",
+        "als",
+        "alsjeblieft",
+        "altijd",
+        "ander",
+        "andere",
+        "anders",
+        "angst",
+        "antwoord",
+        "antwoorden",
+        "appel",
+        "arm",
+        "auto",
+        "avond",
+        "avondeten",
+        "baan",
+        "baby",
+        "bad",
+        "bal",
+        "bang",
+        "bank",
+        "basis",
+        "bed",
+        "bedekken",
+        "bedreiging",
+        "bedreven",
+        "been",
+        "beer",
+        "beest",
+        "beetje",
+        "begin",
+        "begrijpen",
+        "begrip",
+        "behalve",
+        "beide",
+        "beker",
+        "bel",
+        "belangrijk",
+        "bellen",
+        "belofte",
+        "beneden",
+        "benzine",
+        "berg",
+        "beroemd",
+        "beroep",
+        "bescherm",
+        "beslissen",
+        "best",
+        "betalen",
+        "beter",
+        "bevatten",
+        "bewegen",
+        "bewolkt",
+        "bezoek",
+        "bibliotheek",
+        "bieden",
+        "bij",
+        "bijna",
+        "bijten",
+        "bijvoorbeeld",
+        "bijzonder",
+        "binnen",
+        "binnenkort",
+        "blad",
+        "blauw",
+        "blazen",
+        "blij",
+        "blijven",
+        "bloed",
+        "bloem",
+        "bodem",
+        "boek",
+        "boerderij",
+        "boete",
+        "boom",
+        "boon",
+        "boord",
+        "boos",
+        "bord",
+        "borstelen",
+        "bos",
+        "bot",
+        "bouwen",
+        "boven",
+        "branden",
+        "brandstof",
+        "breed",
+        "breken",
+        "brengen",
+        "brief",
+        "broer",
+        "broek",
+        "brood",
+        "brug",
+        "bruikbaar",
+        "bruiloft",
+        "bruin",
+        "bui",
+        "buiten",
+        "bureau",
+        "buren",
+        "bus",
+        "buurman",
+        "buurvrouw",
+        "cadeau",
+        "chocolade",
+        "cirkel",
+        "comfortabel",
+        "compleet",
+        "computer",
+        "conditie",
+        "controle",
+        "cool",
+        "correct",
+        "daar",
+        "daarom",
+        "dag",
+        "dak",
+        "dan",
+        "dansen",
+        "dapper",
+        "dat",
+        "de",
+        "deel",
+        "deken",
+        "deksel",
+        "delen",
+        "derde",
+        "deze",
+        "dichtbij",
+        "dienen",
+        "diep",
+        "dier",
+        "dik",
+        "ding",
+        "dit",
+        "dochter",
+        "doen",
+        "dom",
+        "donker",
+        "dood",
+        "door",
+        "doorzichtig",
+        "doos",
+        "dorp",
+        "draad",
+        "draaien",
+        "dragen",
+        "drie",
+        "drijven",
+        "drinken",
+        "drogen",
+        "dromen",
+        "droog",
+        "druk",
+        "dubbel",
+        "dun",
+        "dus",
+        "duur",
+        "duwen",
+        "echt",
+        "een",
+        "één",
+        "eend",
+        "eenheid",
+        "eenzaam",
+        "eerste",
+        "eeuw",
+        "effect",
+        "ei",
+        "eigen",
+        "eiland",
+        "einde",
+        "eis",
+        "elektrisch",
+        "elk",
+        "en",
+        "enkele",
+        "enthousiast",
+        "erg",
+        "eten",
+        "even",
+        "examen",
+        "extreem",
+        "falen",
+        "familie",
+        "feest",
+        "feit",
+        "fel",
+        "fijn",
+        "film",
+        "fit",
+        "fles",
+        "foto",
+        "fout",
+        "fris",
+        "fruit",
+        "gaan",
+        "gat",
+        "gebeuren",
+        "gebeurtenis",
+        "gebied",
+        "geboorte",
+        "geboren",
+        "gebruik",
+        "gebruikelijk",
+        "gebruiken",
+        "gedrag",
+        "gedragen",
+        "geel",
+        "geen",
+        "gehoorzamen",
+        "geit",
+        "geld",
+        "geliefde",
+        "gelijk",
+        "geloof",
+        "geluid",
+        "geluk",
+        "gemak",
+        "gemakkelijk",
+        "gemeen",
+        "genieten",
+        "genoeg",
+        "genot",
+        "gerecht",
+        "gereedschap",
+        "geschikt",
+        "gespannen",
+        "geur",
+        "gevaar",
+        "gevaarlijk",
+        "gevangenis",
+        "geven",
+        "gevolg",
+        "gewicht",
+        "gewoon",
+        "gezicht",
+        "gezond",
+        "gif",
+        "gisteren",
+        "glad",
+        "glas",
+        "glimlach",
+        "god",
+        "goed",
+        "goedkoop",
+        "goud",
+        "graf",
+        "grap",
+        "grappig",
+        "gras",
+        "grens",
+        "grijs",
+        "groeien",
+        "groen",
+        "groente",
+        "groep",
+        "grof",
+        "grond",
+        "groot",
+        "grootmoeder",
+        "grootvader",
+        "haan",
+        "haar",
+        "haast",
+        "hal",
+        "halen",
+        "half",
+        "hallo",
+        "hamer",
+        "hand",
+        "hard",
+        "hart",
+        "haten",
+        "hebben",
+        "heel",
+        "heet",
+        "helder",
+        "helft",
+        "help",
+        "hem",
+        "hemel",
+        "hen",
+        "herfst",
+        "herinneren",
+        "hert",
+        "het",
+        "heuvel",
+        "hier",
+        "hij",
+        "hobby",
+        "hoe",
+        "hoed",
+        "hoek",
+        "hoeveel",
+        "hoeveelheid",
+        "hoewel",
+        "hond",
+        "honderd",
+        "honger",
+        "hoofd",
+        "hoog",
+        "hoogte",
+        "hoop",
+        "horen",
+        "hotel",
+        "houden",
+        "huilen",
+        "huis",
+        "hun",
+        "huren",
+        "hut",
+        "huur",
+        "idee",
+        "ieder",
+        "iedereen",
+        "iemand",
+        "iets",
+        "ijs",
+        "ijzer",
+        "ik",
+        "in",
+        "instrument",
+        "ja",
+        "jaar",
+        "jagen",
+        "jas",
+        "jij",
+        "jong",
+        "jongen",
+        "jouw",
+        "jullie",
+        "kaars",
+        "kaart",
+        "kaas",
+        "kamer",
+        "kans",
+        "kant",
+        "kantoor",
+        "kap",
+        "kast",
+        "kasteel",
+        "kat",
+        "kennen",
+        "kennis",
+        "keuken",
+        "keus",
+        "kiezen",
+        "kijken",
+        "kind",
+        "kip",
+        "kist",
+        "klaar",
+        "klas",
+        "klasse",
+        "kleden",
+        "klein",
+        "kleren",
+        "kleur",
+        "klimmen",
+        "klok",
+        "kloppen",
+        "klopt",
+        "knie",
+        "knippen",
+        "koers",
+        "koffer",
+        "koffie",
+        "kok",
+        "koken",
+        "kom",
+        "komen",
+        "koning",
+        "koningin",
+        "koorts",
+        "kop",
+        "kopen",
+        "kort",
+        "kost",
+        "kosten",
+        "koud",
+        "kraam",
+        "kracht",
+        "krant",
+        "krijgen",
+        "kruis",
+        "kuil",
+        "kunnen",
+        "kunst",
+        "laag",
+        "laat",
+        "laatst",
+        "lach",
+        "lachen",
+        "ladder",
+        "laken",
+        "lamp",
+        "land",
+        "lang",
+        "langs",
+        "langzaam",
+        "laten",
+        "leeftijd",
+        "leeg",
+        "leerling",
+        "leeuw",
+        "leger",
+        "leiden",
+        "lenen",
+        "lengte",
+        "lepel",
+        "leren",
+        "les",
+        "leuk",
+        "leven",
+        "lezen",
+        "lichaam",
+        "licht",
+        "liefde",
+        "liegen",
+        "liggen",
+        "lijk",
+        "lijken",
+        "liniaal",
+        "links",
+        "lip",
+        "list",
+        "lomp",
+        "lood",
+        "lopen",
+        "los",
+        "lot",
+        "lucht",
+        "lui",
+        "luisteren",
+        "lunch",
+        "maag",
+        "maal",
+        "maaltijd",
+        "maan",
+        "maand",
+        "maar",
+        "maat",
+        "machine",
+        "maken",
+        "makkelijk",
+        "mama",
+        "man",
+        "mand",
+        "manier",
+        "map",
+        "markeren",
+        "markt",
+        "me",
+        "medicijn",
+        "meel",
+        "meer",
+        "meerdere",
+        "meest",
+        "meisje",
+        "melk",
+        "meneer",
+        "mengsel",
+        "mensen",
+        "mes",
+        "met",
+        "meubel",
+        "mevrouw",
+        "middel",
+        "midden",
+        "mij",
+        "mijn",
+        "miljoen",
+        "min",
+        "minder",
+        "minuut",
+        "mis",
+        "missen",
+        "mits",
+        "model",
+        "modern",
+        "moeder",
+        "moeilijk",
+        "moeten",
+        "mogelijk",
+        "mogen",
+        "moment",
+        "mond",
+        "mooi",
+        "moord",
+        "moorden",
+        "morgen",
+        "munt",
+        "muziek",
+        "na",
+        "naald",
+        "naam",
+        "naar",
+        "naast",
+        "nacht",
+        "nat",
+        "natuur",
+        "natuurlijk",
+        "nee",
+        "neer",
+        "negen",
+        "nek",
+        "nemen",
+        "net",
+        "netjes",
+        "neus",
+        "niet",
+        "niets",
+        "nieuw",
+        "nieuws",
+        "nobel",
+        "noch",
+        "nodig",
+        "noemen",
+        "nog",
+        "nood",
+        "nooit",
+        "noord",
+        "noot",
+        "normaal",
+        "nu",
+        "nul",
+        "nummer",
+        "object",
+        "oceaan",
+        "ochtend",
+        "oefening",
+        "of",
+        "offer",
+        "olie",
+        "olifant",
+        "om",
+        "oma",
+        "onder",
+        "onderwerp",
+        "onderzoek",
+        "oneven",
+        "ongeluk",
+        "ons",
+        "ontsnappen",
+        "ontbijt",
+        "ontdekken",
+        "ontmoeten",
+        "ontvangen",
+        "ontwikkelen",
+        "onze",
+        "oog",
+        "ooit",
+        "ook",
+        "oom",
+        "oor",
+        "oorlog",
+        "oorzaak",
+        "oost",
+        "op",
+        "opa",
+        "opeens",
+        "open",
+        "openlijk",
+        "opleiding",
+        "opnemen",
+        "oranje",
+        "orde",
+        "oud",
+        "ouder",
+        "over",
+        "overal",
+        "overeenkomen",
+        "overleden",
+        "overvallen",
+        "paar",
+        "paard",
+        "pad",
+        "pagina",
+        "pan",
+        "papa",
+        "papier",
+        "park",
+        "partner",
+        "pas",
+        "passeren",
+        "pen",
+        "peper",
+        "per",
+        "perfect",
+        "periode",
+        "persoon",
+        "piano",
+        "pijn",
+        "pistool",
+        "plaat",
+        "plaatje",
+        "plaats",
+        "plafond",
+        "plank",
+        "plant",
+        "plastic",
+        "plat",
+        "plattegrond",
+        "plein",
+        "plus",
+        "poes",
+        "politie",
+        "poort",
+        "populair",
+        "positie",
+        "postzegel",
+        "potlood",
+        "praten",
+        "presenteren",
+        "prijs",
+        "prins",
+        "prinses",
+        "privé",
+        "proberen",
+        "probleem",
+        "product",
+        "provincie",
+        "publiek",
+        "punt",
+        "raak",
+        "raam",
+        "radio",
+        "raken",
+        "rapport",
+        "recht",
+        "rechtdoor",
+        "rechts",
+        "rechtvaardig",
+        "redden",
+        "reeds",
+        "regen",
+        "reiken",
+        "reizen",
+        "rekenmachine",
+        "rennen",
+        "repareren",
+        "rest",
+        "restaurant",
+        "resultaat",
+        "richting",
+        "rijk",
+        "rijst",
+        "rijzen",
+        "ring",
+        "rok",
+        "rond",
+        "rood",
+        "rook",
+        "rots",
+        "roze",
+        "rubber",
+        "ruiken",
+        "ruimte",
+        "samen",
+        "sap",
+        "schaap",
+        "schaar",
+        "schaduw",
+        "scheiden",
+        "scherp",
+        "schetsen",
+        "schieten",
+        "schijnen",
+        "schip",
+        "school",
+        "schoon",
+        "schouder",
+        "schreeuw",
+        "schreeuwen",
+        "schrijven",
+        "schudden",
+        "seconde",
+        "sex",
+        "signaal",
+        "simpel",
+        "sinds",
+        "slaapkamer",
+        "slapen",
+        "slecht",
+        "sleutel",
+        "slim",
+        "slot",
+        "sluiten",
+        "smaak",
+        "smal",
+        "sneeuw",
+        "snel",
+        "snelheid",
+        "snijden",
+        "soep",
+        "sok",
+        "soms",
+        "soort",
+        "sorry",
+        "speciaal",
+        "spel",
+        "spelen",
+        "sport",
+        "spreken",
+        "springen",
+        "staal",
+        "stad",
+        "stap",
+        "start",
+        "station",
+        "steen",
+        "stelen",
+        "stem",
+        "stempel",
+        "ster",
+        "sterk",
+        "steun",
+        "stil",
+        "stilte",
+        "stoel",
+        "stof",
+        "stoffig",
+        "stom",
+        "stop",
+        "storm",
+        "straat",
+        "straffen",
+        "structuur",
+        "student",
+        "studie",
+        "stuk",
+        "succes",
+        "suiker",
+        "taal",
+        "taart",
+        "tafel",
+        "tak",
+        "tamelijk",
+        "tand",
+        "tante",
+        "tas",
+        "taxi",
+        "te",
+        "team",
+        "teen",
+        "tegen",
+        "teken",
+        "tekenen",
+        "telefoon",
+        "televisie",
+        "tellen",
+        "tennis",
+        "terug",
+        "terugkomst",
+        "terwijl",
+        "test",
+        "tevreden",
+        "thee",
+        "thuis",
+        "tien",
+        "tijd",
+        "titel",
+        "toekomst",
+        "toen",
+        "toename",
+        "totaal",
+        "traan",
+        "tram",
+        "trein",
+        "trekken",
+        "trouwen",
+        "trui",
+        "tuin",
+        "tussen",
+        "tweede",
+        "u",
+        "uit",
+        "uitleggen",
+        "uitnodigen",
+        "uitvinden",
+        "uitzoeken",
+        "uur",
+        "vaak",
+        "vaarwel",
+        "vader",
+        "vak",
+        "vakantie",
+        "vallen",
+        "vals",
+        "van",
+        "vandaag",
+        "vangen",
+        "vanmorgen",
+        "vannacht",
+        "varken",
+        "vast",
+        "vechten",
+        "veel",
+        "veer",
+        "veilig",
+        "ver",
+        "veranderen",
+        "verandering",
+        "verder",
+        "verdienen",
+        "verdrietig",
+        "verenigen",
+        "verf",
+        "vergelijkbaar",
+        "vergelijken",
+        "vergelijking",
+        "vergeten",
+        "vergeven",
+        "vergissen",
+        "verhaal",
+        "verhoging",
+        "verjaardag",
+        "verkeerd",
+        "verkopen",
+        "verlaten",
+        "verleden",
+        "verliezen",
+        "vernietigen",
+        "veroveren",
+        "verrassen",
+        "vers",
+        "verschil",
+        "verschrikkelijk",
+        "verspreiden",
+        "verstand",
+        "verstoppen",
+        "versturen",
+        "vertellen",
+        "vertrekken",
+        "vertrouwen",
+        "verwachten",
+        "verwijderen",
+        "verzamelen",
+        "verzameling",
+        "vet",
+        "vier",
+        "vierkant",
+        "vies",
+        "vijand",
+        "vijf",
+        "vijver",
+        "vinden",
+        "vinger",
+        "vis",
+        "vlag",
+        "vlees",
+        "vlieg",
+        "vliegtuig",
+        "vloer",
+        "voeden",
+        "voedsel",
+        "voelen",
+        "voet",
+        "voetbal",
+        "vogel",
+        "vol",
+        "volgende",
+        "volgorde",
+        "voor",
+        "voorbeeld",
+        "voorkomen",
+        "voorzichtig",
+        "voorzien",
+        "vork",
+        "vorm",
+        "vos",
+        "vouwen",
+        "vraag",
+        "vragen",
+        "vrede",
+        "vreemd",
+        "vreemde",
+        "vriend",
+        "vriendelijk",
+        "vriezen",
+        "vrij",
+        "vrijheid",
+        "vroeg",
+        "vroeger",
+        "vrouw",
+        "vullen",
+        "vuur",
+        "waar",
+        "waarom",
+        "waarschijnlijk",
+        "wachten",
+        "wakker",
+        "wanneer",
+        "want",
+        "wapen",
+        "warm",
+        "wassen",
+        "wat",
+        "water",
+        "we",
+        "week",
+        "weer",
+        "weg",
+        "welke",
+        "welkom",
+        "wens",
+        "wereld",
+        "werelddeel",
+        "werk",
+        "west",
+        "wetenschap",
+        "wie",
+        "wiel",
+        "wij",
+        "wijn",
+        "wijs",
+        "wild",
+        "willen",
+        "wind",
+        "winkel",
+        "winnen",
+        "winter",
+        "wissen",
+        "wit",
+        "wolf",
+        "wolk",
+        "wonder",
+        "woord",
+        "woud",
+        "wreed",
+        "zaak",
+        "zacht",
+        "zak",
+        "zand",
+        "zee",
+        "zeep",
+        "zeer",
+        "zeggen",
+        "zeil",
+        "zeker",
+        "zelfde",
+        "zes",
+        "zetten",
+        "zeven",
+        "ziek",
+        "ziekenhuis",
+        "ziel",
+        "zien",
+        "zij",
+        "zijn",
+        "zilver",
+        "zingen",
+        "zinken",
+        "zitten",
+        "zo",
+        "zoals",
+        "zoeken",
+        "zoet",
+        "zomer",
+        "zon",
+        "zonder",
+        "zonnig",
+        "zoon",
+        "zorg",
+        "zorgen",
+        "zou",
+        "zout",
+        "zuid",
+        "zulke",
+        "zullen",
+        "zus",
+        "zwaar",
+        "zwak",
+        "zwembad",
+        "zwemmen",
+    )
+
+    parts_of_speech: Dict[str, tuple] = {}
diff --git a/faker/providers/lorem/nl_NL/__init__.py b/faker/providers/lorem/nl_NL/__init__.py
new file mode 100644
index 00000000..0c8e88e9
--- /dev/null
+++ b/faker/providers/lorem/nl_NL/__init__.py
@@ -0,0 +1,14 @@
+from typing import Dict
+
+from .. import Provider as LoremProvider
+from ..nl_BE import Provider as LoremProviderNL_BE
+
+
+class Provider(LoremProvider):
+    """Implement lorem provider for ``nl_NL`` locale.
+
+    Source: https://nl.wiktionary.org/wiki/WikiWoordenboek:Lijst_met_1000_basiswoorden
+    """
+
+    word_list = LoremProviderNL_BE.word_list
+    parts_of_speech: Dict[str, tuple] = {}
diff --git a/faker/providers/python/__init__.py b/faker/providers/python/__init__.py
index 8391c604..3cf61157 100644
--- a/faker/providers/python/__init__.py
+++ b/faker/providers/python/__init__.py
@@ -55,6 +55,40 @@ class Provider(BaseProvider):
             allowed_types = ()
         return tuple(value_types) + tuple(allowed_types)
 
+    def pyobject(
+        self,
+        object_type: Optional[Type[Union[bool, str, float, int, tuple, set, list, Iterable, dict]]] = None,
+    ) -> Optional[Union[bool, str, float, int, tuple, set, list, Iterable, dict]]:
+        """
+        Generates a random object passing the type desired.
+
+        :object_type: the type of the object to generate.
+        :return: the random object generated.
+        :raises ValueError: if the object type passed is not supported
+        """
+        if object_type is None:
+            return None
+        elif object_type == bool:
+            return self.pybool()
+        elif object_type == str:
+            return self.pystr()
+        elif object_type == float:
+            return self.pyfloat()
+        elif object_type == int:
+            return self.pyint()
+        elif object_type == tuple:
+            return self.pytuple()
+        elif object_type == set:
+            return self.pyset()
+        elif object_type == list:
+            return self.pylist()
+        elif object_type == Iterable:
+            return self.pyiterable()
+        elif object_type == dict:
+            return self.pydict()
+        else:
+            raise ValueError(f"Object type `{object_type}` is not supported by `pyobject` function")
+
     def pybool(self, truth_probability: int = 50) -> bool:
         """
         Generates a random boolean, optionally biased towards `True` or `False`.
@@ -144,20 +178,23 @@ class Provider(BaseProvider):
 
         sign = ""
         if (min_value is not None) or (max_value is not None):
+            # Copy values to ensure we're not modifying the original values and thus going out of bounds
+            left_min_value = min_value
+            left_max_value = max_value
             # Make sure left_digits still respected
             if left_digits is not None:
                 if max_value is None:
-                    max_value = 10**left_digits  # minus smallest representable, adjusted later
+                    left_max_value = 10**left_digits  # minus smallest representable, adjusted later
                 if min_value is None:
-                    min_value = -(10**left_digits)  # plus smallest representable, adjusted later
+                    left_min_value = -(10**left_digits)  # plus smallest representable, adjusted later
 
             if max_value is not None and max_value < 0:
-                max_value += 1  # as the random_int will be generated up to max_value - 1
+                left_max_value += 1  # as the random_int will be generated up to max_value - 1
             if min_value is not None and min_value < 0:
-                min_value += 1  # as we then append digits after the left_number
+                left_min_value += 1  # as we then append digits after the left_number
             left_number = self._safe_random_int(
-                min_value,
-                max_value,
+                left_min_value,
+                left_max_value,
                 positive,
             )
         else:
@@ -178,11 +215,17 @@ class Provider(BaseProvider):
             result = min(result, 10**left_digits - 1)
             result = max(result, -(10**left_digits + 1))
 
-        # It's possible for the result to end up > than max_value
-        # This is a quick hack to ensure result is always smaller.
+        # It's possible for the result to end up > than max_value or < than min_value
+        # When this happens we introduce some variance so we're not always the exactly the min_value or max_value.
+        # Which can happen a lot depending on the difference of the values.
+        # Ensure the variance is bound by the difference between the max and min
         if max_value is not None:
             if result > max_value:
-                result = result - (result - max_value)
+                result = result - (result - max_value + self.generator.random.uniform(0, max_value - min_value))
+        if min_value is not None:
+            if result < min_value:
+                result = result + (min_value - result + self.generator.random.uniform(0, max_value - min_value))
+
         return result
 
     def _safe_random_int(self, min_value: float, max_value: float, positive: bool) -> int:


Test patch:
diff --git a/tests/providers/test_address.py b/tests/providers/test_address.py
index 0576484e..0a0e2cbb 100644
--- a/tests/providers/test_address.py
+++ b/tests/providers/test_address.py
@@ -519,14 +519,29 @@ class TestEnUS:
         for _ in range(num_samples):
             state_abbr = faker.state_abbr()
             assert isinstance(state_abbr, str)
-            states_and_territories = EnUsAddressProvider.states_and_territories_abbr
+            states_and_territories = EnUsAddressProvider.known_usps_abbr
             assert state_abbr in states_and_territories
 
+    def test_state_abbr_states_only(self, faker, num_samples):
+        for _ in range(num_samples):
+            state_abbr = faker.state_abbr(include_territories=False, include_freely_associated_states=False)
+            assert isinstance(state_abbr, str)
+            assert state_abbr in EnUsAddressProvider.states_abbr
+
     def test_state_abbr_no_territories(self, faker, num_samples):
         for _ in range(num_samples):
             state_abbr = faker.state_abbr(include_territories=False)
             assert isinstance(state_abbr, str)
-            assert state_abbr in EnUsAddressProvider.states_abbr
+            assert (
+                state_abbr in EnUsAddressProvider.states_abbr
+                or state_abbr in EnUsAddressProvider.freely_associated_states_abbr
+            )
+
+    def test_state_abbr_no_freely_associated_states(self, faker, num_samples):
+        for _ in range(num_samples):
+            state_abbr = faker.state_abbr(include_freely_associated_states=False)
+            assert isinstance(state_abbr, str)
+            assert state_abbr in EnUsAddressProvider.states_abbr or state_abbr in EnUsAddressProvider.territories_abbr
 
     def test_postcode(self, faker, num_samples):
         for _ in range(num_samples):
@@ -536,7 +551,7 @@ class TestEnUS:
 
     def test_postcode_in_state(self, faker, num_samples):
         for _ in range(num_samples):
-            for state_abbr in EnUsAddressProvider.states_and_territories_abbr:
+            for state_abbr in EnUsAddressProvider.known_usps_abbr:
                 code = faker.postcode_in_state(state_abbr)
                 assert re.fullmatch(r"\d{5}", code)
                 assert int(code) >= EnUsAddressProvider.states_postcode[state_abbr][0]
@@ -553,7 +568,7 @@ class TestEnUS:
 
     def test_zipcode_in_state(self, faker, num_samples):
         for _ in range(num_samples):
-            for state_abbr in EnUsAddressProvider.states_and_territories_abbr:
+            for state_abbr in EnUsAddressProvider.known_usps_abbr:
                 code = faker.zipcode_in_state(state_abbr)
                 assert re.fullmatch(r"\d{5}", code)
                 assert int(code) >= EnUsAddressProvider.states_postcode[state_abbr][0]
@@ -611,6 +626,12 @@ class TestEnUS:
         with pytest.raises(Exception):
             faker.postalcode_in_state("XX")
 
+    def test_state_abbr_determinism(self, faker):
+        faker.seed_instance(0)
+        first = faker.state_abbr()
+        faker.seed_instance(0)
+        assert faker.state_abbr() == first
+
 
 class TestEsCo:
     """Test es_CO address provider methods"""
diff --git a/tests/providers/test_automotive.py b/tests/providers/test_automotive.py
index 6d3f27af..7768b531 100644
--- a/tests/providers/test_automotive.py
+++ b/tests/providers/test_automotive.py
@@ -310,3 +310,9 @@ class TestDeCh(_SimpleAutomotiveTestMixin):
     """Test de_CH automotive provider methods"""
 
     license_plate_pattern: Pattern = re.compile(r"[A-Z]{2}-\d{1,3}\s?\d{0,3}")
+
+
+class TestNlBe(_SimpleAutomotiveTestMixin):
+    """Test nl_BE automotive provider methods"""
+
+    license_plate_pattern: Pattern = re.compile(r"(\d{3}-[A-Z]{3})|" r"([A-Z]{3}-\d{3})|" r"([1-2]-[A-Z]{3}-\d{3})")
diff --git a/tests/providers/test_company.py b/tests/providers/test_company.py
index 85dd1ec3..13be6705 100644
--- a/tests/providers/test_company.py
+++ b/tests/providers/test_company.py
@@ -14,6 +14,7 @@ from faker.providers.company.hu_HU import Provider as HuHuCompanyProvider
 from faker.providers.company.hy_AM import Provider as HyAmCompanyProvider
 from faker.providers.company.it_IT import Provider as ItItCompanyProvider
 from faker.providers.company.ja_JP import Provider as JaJpCompanyProvider
+from faker.providers.company.nl_BE import Provider as NlBeCompanyProvider
 from faker.providers.company.nl_NL import Provider as NlNlCompanyProvider
 from faker.providers.company.pl_PL import Provider as PlPlCompanyProvider
 from faker.providers.company.pl_PL import company_vat_checksum, local_regon_checksum, regon_checksum
@@ -465,3 +466,13 @@ class TestElGr:
             suffix = faker.company_suffix()
             assert isinstance(suffix, str)
             assert suffix in ElGrCompanyProvider.company_suffixes
+
+
+class TestNlBe:
+    """Test nl_BE company provider methods"""
+
+    def test_company_suffix(self, faker, num_samples):
+        for _ in range(num_samples):
+            suffix = faker.company_suffix()
+            assert isinstance(suffix, str)
+            assert suffix in NlBeCompanyProvider.company_suffixes
diff --git a/tests/providers/test_lorem.py b/tests/providers/test_lorem.py
index 0ea37933..40761a27 100644
--- a/tests/providers/test_lorem.py
+++ b/tests/providers/test_lorem.py
@@ -9,6 +9,7 @@ from faker.providers.lorem.de_AT import Provider as DeAtLoremProvider
 from faker.providers.lorem.de_DE import Provider as DeDeLoremProvider
 from faker.providers.lorem.en_US import Provider as EnUsLoremProvider
 from faker.providers.lorem.fa_IR import Provider as FaIrLoremProvider
+from faker.providers.lorem.nl_BE import Provider as NlBeLoremProvider
 
 
 class TestLoremProvider:
@@ -572,3 +573,75 @@ class TestDeAt:
         for _ in range(num_samples):
             words = faker.words(num_words)
             assert all(isinstance(word, str) and word in DeAtLoremProvider.word_list for word in words)
+
+
+class TestNlBe:
+    """Test ```nl_BE``` lorem provider
+
+    Copied from the TestDeDe class, but with the word_list from the NlBeLoremProvider.
+    """
+
+    word_list = [word.lower() for word in NlBeLoremProvider.word_list]
+
+    def test_paragraph(self, faker, num_samples):
+        num_sentences = 10
+        for _ in range(num_samples):
+            paragraph = faker.paragraph(nb_sentences=num_sentences)
+            assert isinstance(paragraph, str)
+            words = paragraph.replace(".", "").split()
+            assert all(word.lower() in self.word_list for word in words)
+
+    def test_paragraphs(self, faker, num_samples):
+        num_paragraphs = 5
+        for _ in range(num_samples):
+            paragraphs = faker.paragraphs(nb=num_paragraphs)
+            for paragraph in paragraphs:
+                assert isinstance(paragraph, str)
+                words = paragraph.replace(".", "").split()
+                assert all(word.lower() in self.word_list for word in words)
+
+    def test_sentence(self, faker, num_samples):
+        num_words = 10
+        for _ in range(num_samples):
+            sentence = faker.sentence(nb_words=num_words)
+            assert isinstance(sentence, str)
+            words = sentence.replace(".", "").split()
+            assert all(word.lower() in self.word_list for word in words)
+
+    def test_sentences(self, faker, num_samples):
+        num_sentences = 5
+        for _ in range(num_samples):
+            sentences = faker.sentences(nb=num_sentences)
+            for sentence in sentences:
+                assert isinstance(sentence, str)
+                words = sentence.replace(".", "").split()
+                assert all(word.lower() in self.word_list for word in words)
+
+    def test_text(self, faker, num_samples):
+        num_chars = 25
+        for _ in range(num_samples):
+            text = faker.text(max_nb_chars=num_chars)
+            assert isinstance(text, str)
+            words = re.sub(r"[.\n]+", " ", text).split()
+            assert all(word.lower() in self.word_list for word in words)
+
+    def test_texts(self, faker, num_samples):
+        num_texts = 5
+        num_chars = 25
+        for _ in range(num_samples):
+            texts = faker.texts(max_nb_chars=num_chars, nb_texts=num_texts)
+            for text in texts:
+                assert isinstance(text, str)
+                words = re.sub(r"[.\n]+", " ", text).split()
+                assert all(word.lower() in self.word_list for word in words)
+
+    def test_word(self, faker, num_samples):
+        for _ in range(num_samples):
+            word = faker.word()
+            assert isinstance(word, str) and word in NlBeLoremProvider.word_list
+
+    def test_words(self, faker, num_samples):
+        num_words = 5
+        for _ in range(num_samples):
+            words = faker.words(num_words)
+            assert all(isinstance(word, str) and word in NlBeLoremProvider.word_list for word in words)
diff --git a/tests/providers/test_python.py b/tests/providers/test_python.py
index 99f4866d..27a2a69e 100644
--- a/tests/providers/test_python.py
+++ b/tests/providers/test_python.py
@@ -3,6 +3,7 @@ import sys
 import unittest
 import warnings
 
+from typing import Iterable, Optional, Union
 from unittest.mock import patch
 
 import pytest
@@ -10,6 +11,23 @@ import pytest
 from faker import Faker
 
 
+@pytest.mark.parametrize("object_type", (None, bool, str, float, int, tuple, set, list, Iterable, dict))
+def test_pyobject(
+    object_type: Optional[Union[bool, str, float, int, tuple, set, list, Iterable, dict]],
+):
+    random_object = Faker().pyobject(object_type=object_type)
+    if object_type is None:
+        assert random_object is None
+    else:
+        assert isinstance(random_object, object_type)
+
+
+@pytest.mark.parametrize("object_type", (object, type, callable))
+def test_pyobject_with_unknown_object_type(object_type):
+    with pytest.raises(ValueError, match=f"Object type `{object_type}` is not supported by `pyobject` function"):
+        assert Faker().pyobject(object_type=object_type)
+
+
 @pytest.mark.parametrize(
     "mock_random_number_source, right_digits, expected_decimal_part",
     (
@@ -181,6 +199,17 @@ class TestPyfloat(unittest.TestCase):
         self.assertLessEqual(result, 100)
         self.assertGreater(result, 0)
 
+    def test_max_and_min_value_positive_with_decimals(self):
+        """
+        Combining the max_value and min_value keyword arguments with
+        positive values for each produces numbers that obey both of
+        those constraints.
+        """
+        for _ in range(1000):
+            result = self.fake.pyfloat(min_value=100.123, max_value=200.321)
+            self.assertLessEqual(result, 200.321)
+            self.assertGreaterEqual(result, 100.123)
+
     def test_max_and_min_value_negative(self):
         """
         Combining the max_value and min_value keyword arguments with
@@ -192,6 +221,17 @@ class TestPyfloat(unittest.TestCase):
         self.assertLessEqual(result, -100)
         self.assertGreaterEqual(result, -200)
 
+    def test_max_and_min_value_negative_with_decimals(self):
+        """
+        Combining the max_value and min_value keyword arguments with
+        negative values for each produces numbers that obey both of
+        those constraints.
+        """
+        for _ in range(1000):
+            result = self.fake.pyfloat(max_value=-100.123, min_value=-200.321)
+            self.assertLessEqual(result, -100.123)
+            self.assertGreaterEqual(result, -200.321)
+
     def test_positive_and_min_value_incompatible(self):
         """
         An exception should be raised if positive=True is set, but