factory.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. """ Mixer factories. """
  2. import datetime
  3. import decimal
  4. import inspect
  5. from . import _compat as _, mix_types as t
  6. from ._faker import faker
  7. class GenFactoryMeta(type):
  8. """ Precache generators. """
  9. def __new__(mcs, name, bases, params):
  10. generators = dict()
  11. fakers = dict()
  12. types = dict()
  13. for cls in bases:
  14. if isinstance(cls, GenFactoryMeta):
  15. generators.update(cls.generators)
  16. fakers.update(cls.fakers)
  17. types.update(cls.types)
  18. fakers.update(params.get('fakers', dict()))
  19. types.update(params.get('types', dict()))
  20. types = dict(mcs.__flat_keys(types))
  21. if types:
  22. for atype, btype in types.items():
  23. factory = generators.get(btype)
  24. if factory:
  25. generators[atype] = factory
  26. generators.update(params.get('generators', dict()))
  27. generators = dict(mcs.__flat_keys(generators))
  28. params['generators'] = generators
  29. params['fakers'] = fakers
  30. params['types'] = types
  31. return super(GenFactoryMeta, mcs).__new__(mcs, name, bases, params)
  32. @staticmethod
  33. def __flat_keys(d):
  34. for key, value in d.items():
  35. if isinstance(key, (tuple, list)):
  36. for k in key:
  37. yield k, value
  38. continue
  39. yield key, value
  40. class GenFactory(_.with_metaclass(GenFactoryMeta)):
  41. """ Make generators for types. """
  42. generators = {
  43. bool: faker.pybool,
  44. float: faker.pyfloat,
  45. int: faker.random_int,
  46. str: faker.pystr,
  47. bytes: faker.pybytes,
  48. list: faker.pylist,
  49. set: faker.pyset,
  50. tuple: faker.pytuple,
  51. dict: faker.pydict,
  52. datetime.date: faker.date,
  53. datetime.datetime: faker.date_time,
  54. datetime.time: faker.time,
  55. decimal.Decimal: faker.pydecimal,
  56. t.BigInteger: faker.big_integer,
  57. t.EmailString: faker.email,
  58. t.HostnameString: faker.domain_name,
  59. t.IP4String: faker.ipv4,
  60. t.IP6String: faker.ipv6,
  61. t.IPString: faker.ip_generic,
  62. t.NullOrBoolean: faker.null_boolean,
  63. t.PositiveDecimal: faker.positive_decimal,
  64. t.PositiveInteger: faker.positive_integer,
  65. t.PositiveSmallInteger: faker.small_positive_integer,
  66. t.SmallInteger: faker.small_integer,
  67. t.Text: faker.text,
  68. t.URL: faker.url,
  69. t.UUID: faker.uuid,
  70. type(None): '',
  71. }
  72. fakers = {
  73. ('address', str): faker.street_address,
  74. ('body', str): faker.text,
  75. ('category', str): faker.genre,
  76. ('city', str): faker.city,
  77. ('company', str): faker.company,
  78. ('content', str): faker.text,
  79. ('country', str): faker.country,
  80. ('description', str): faker.text,
  81. ('domain', str): faker.domain_name,
  82. ('email', str): faker.email,
  83. ('first_name', str): faker.first_name,
  84. ('firstname', str): faker.first_name,
  85. ('genre', str): faker.genre,
  86. ('last_name', str): faker.last_name,
  87. ('lastname', str): faker.last_name,
  88. ('lat', float): faker.latitude,
  89. ('latitude', float): faker.latitude,
  90. ('login', str): faker.user_name,
  91. ('lon', float): faker.longitude,
  92. ('longitude', float): faker.longitude,
  93. ('name', str): faker.name,
  94. ('percent', decimal.Decimal): faker.percent_decimal,
  95. ('percent', int): faker.percent,
  96. ('phone', str): faker.phone_number,
  97. ('site', str): faker.url,
  98. ('slug', str): faker.slug,
  99. ('street', str): faker.street_name,
  100. ('time_zone', str): faker.timezone,
  101. ('timezone', str): faker.timezone,
  102. ('title', str): faker.title,
  103. ('url', str): faker.uri,
  104. ('url', t.URL): faker.uri,
  105. ('username', str): faker.user_name,
  106. ('uuid', None): faker.uuid,
  107. }
  108. types = {
  109. _.string_types: str,
  110. _.integer_types: int,
  111. }
  112. @classmethod
  113. def cls_to_simple(cls, fcls):
  114. """ Translate class to one of simple base types.
  115. :return type: A simple type for generation
  116. """
  117. if fcls in cls.types:
  118. return cls.types[fcls]
  119. if fcls in cls.generators:
  120. return fcls
  121. if inspect.isclass(fcls):
  122. for stype in cls.types:
  123. if issubclass(fcls, stype):
  124. return cls.types[stype]
  125. return None
  126. @staticmethod
  127. def name_to_simple(fname):
  128. """ Translate name to one of simple base names.
  129. :return str:
  130. """
  131. fname = fname or ''
  132. return fname.lower().strip()
  133. @classmethod
  134. def get_fabric(cls, fcls, fname=None, fake=False):
  135. """ Make a objects fabric based on class and name.
  136. :return function:
  137. """
  138. simple = cls.cls_to_simple(fcls)
  139. func = cls.generators.get(fcls) or cls.generators.get(simple)
  140. if not func and fcls and fcls.__bases__:
  141. func = cls.generators.get(fcls.__bases__[0])
  142. if fname and fake and (fname, simple) in cls.fakers:
  143. fname = cls.name_to_simple(fname)
  144. func = cls.fakers.get((fname, simple)) or func
  145. if func is None:
  146. return False
  147. return func