factory.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import locale as pylocale
  2. import logging
  3. import sys
  4. from importlib import import_module
  5. from typing import Any, List, Optional, Tuple
  6. from .config import AVAILABLE_LOCALES, DEFAULT_LOCALE, PROVIDERS
  7. from .generator import Generator
  8. from .utils.loading import list_module
  9. logger = logging.getLogger(__name__)
  10. # identify if python is being run in interactive mode. If so, disable logging.
  11. inREPL = bool(getattr(sys, "ps1", False))
  12. if inREPL:
  13. logger.setLevel(logging.CRITICAL)
  14. else:
  15. logger.debug("Not in REPL -> leaving logger event level as is.")
  16. class Factory:
  17. @classmethod
  18. def create(
  19. cls,
  20. locale: Optional[str] = None,
  21. providers: Optional[List[str]] = None,
  22. generator: Generator = None,
  23. includes: Optional[List[str]] = None,
  24. # Should we use weightings (more realistic) or weight every element equally (faster)?
  25. # By default, use weightings for backwards compatibility & realism
  26. use_weighting: bool = True,
  27. **config: Any,
  28. ) -> Generator:
  29. if includes is None:
  30. includes = []
  31. # fix locale to package name
  32. locale = locale.replace("-", "_") if locale else DEFAULT_LOCALE
  33. locale = pylocale.normalize(locale).split(".")[0]
  34. if locale not in AVAILABLE_LOCALES:
  35. msg = f"Invalid configuration for faker locale `{locale}`"
  36. raise AttributeError(msg)
  37. config["locale"] = locale
  38. config["use_weighting"] = use_weighting
  39. providers = providers or PROVIDERS
  40. providers += includes
  41. faker = generator or Generator(**config)
  42. for prov_name in providers:
  43. if prov_name == "faker.providers":
  44. continue
  45. prov_cls, lang_found = cls._get_provider_class(prov_name, locale)
  46. provider = prov_cls(faker)
  47. provider.__use_weighting__ = use_weighting
  48. provider.__provider__ = prov_name
  49. provider.__lang__ = lang_found
  50. faker.add_provider(provider)
  51. return faker
  52. @classmethod
  53. def _get_provider_class(cls, provider: str, locale: Optional[str] = "") -> Tuple[Any, Optional[str]]:
  54. provider_class = cls._find_provider_class(provider, locale)
  55. if provider_class:
  56. return provider_class, locale
  57. if locale and locale != DEFAULT_LOCALE:
  58. # fallback to default locale
  59. provider_class = cls._find_provider_class(provider, DEFAULT_LOCALE)
  60. if provider_class:
  61. return provider_class, DEFAULT_LOCALE
  62. # fallback to no locale
  63. provider_class = cls._find_provider_class(provider)
  64. if provider_class:
  65. return provider_class, None
  66. msg = f"Unable to find provider `{provider}` with locale `{locale}`"
  67. raise ValueError(msg)
  68. @classmethod
  69. def _find_provider_class(cls, provider_path: str, locale: Optional[str] = None) -> Any:
  70. provider_module = import_module(provider_path)
  71. if getattr(provider_module, "localized", False):
  72. logger.debug(
  73. "Looking for locale `%s` in provider `%s`.",
  74. locale,
  75. provider_module.__name__,
  76. )
  77. available_locales = list_module(provider_module)
  78. if not locale or locale not in available_locales:
  79. unavailable_locale = locale
  80. locale = getattr(provider_module, "default_locale", DEFAULT_LOCALE)
  81. logger.debug(
  82. "Specified locale `%s` is not available for "
  83. "provider `%s`. Locale reset to `%s` for this "
  84. "provider.",
  85. unavailable_locale,
  86. provider_module.__name__,
  87. locale,
  88. )
  89. else:
  90. logger.debug(
  91. "Provider `%s` has been localized to `%s`.",
  92. provider_module.__name__,
  93. locale,
  94. )
  95. path = f"{provider_path}.{locale}"
  96. provider_module = import_module(path)
  97. else:
  98. logger.debug(
  99. "Provider `%s` does not feature localization. "
  100. "Specified locale `%s` is not utilized for this "
  101. "provider.",
  102. provider_module.__name__,
  103. locale,
  104. )
  105. if locale is not None:
  106. provider_module = import_module(provider_path)
  107. return provider_module.Provider # type: ignore