factory_boy icon indicating copy to clipboard operation
factory_boy copied to clipboard

Share faker generator with Factory Boy's faker registry

Open chriswyatt opened this issue 6 years ago • 5 comments

The problem

No documented way to share an existing faker generator with Factory Boy. Sometimes you might not always want to use the faker library from Factory Boy's Faker class, so it would be nice if Factory Boy could share a common faker generator.

Proposed solution

Allow an easy way to attach an existing faker generator to Factory Boy. Perhaps something like factory.Faker.attach_fake(faker_generator), assuming that's possible?

Workaround

import factory
from faker import Factory as FakerFactory

LOCALE = 'en-US'
fake = FakerFactory.create(locale=LOCALE)
factory.Faker._DEFAULT_LOCALE = LOCALE
factory.Faker._FAKER_REGISTRY[LOCALE] = fake

Extra notes

  • Relates to #407

chriswyatt avatar Jan 10 '19 11:01 chriswyatt

That's indeed a limitation. Do you have some examples of things you run on those custom fakers? This would help designing a relevant API :)

rbarrois avatar Feb 20 '19 13:02 rbarrois

The only thing special about the faker in my projects, is setting the locale, adding custom providers, and also setting the faker seed. Nothing particularly special with my use case.

It was mainly being able to use the custom providers, as I could have lived with the locale being wrong, and the seed not being the same.

Here's an example of a couple of providers I wrote. The rest I can't share, as they're more sensitive (these aren't open source projects):

from faker.providers.date_time import Provider as DateTimeProvider
from faker.providers.python import Provider as PythonProvider
from faker.providers.misc import Provider as MiscProvider

class Rfc3339Provider(DateTimeProvider):

    def rfc_3339(self, utc=False):
        """
        Returns a RFC 3339 string
        """
        tz = pytz.timezone(random.choice(pytz.all_timezones))
        return generate(self.date_time(tzinfo=tz), utc=utc)


class ExtraProvider(PythonProvider, MiscProvider):

    def float_32(self, positive=None):
        fraction = self.generator.random.randrange(0, 1 << 23)
        exponent = self.generator.random.randrange(1, 255)

        if positive is None:
            positive_ = self.boolean()
        else:
            assert positive in (False, True)
            positive_ = positive

        bin_32 = fraction | (exponent << 23) | ((not positive_) << 31)

        (float_32, ) = unpack('>f', pack('>I', bin_32))
        return float_32


fake.add_provider(Rfc3339Provider)
fake.add_provider(ExtraProvider)

The seed stuff is useful for having a chance of replicating inconsistent test failures, as you can feed in the same seed, and hopefully the tests will fail in the same way. Personally I haven't needed to do this (yet), but it's something that could be useful:

seed = random.seed()
# ... store seed in DB
fake.seed(seed)

chriswyatt avatar Feb 20 '19 16:02 chriswyatt

I believe resolving #407 resolves this issue as well. Since this one was created in hope to work around the former. As it is you can add custom providers:

import factory, faker

class MyProvider(faker.providers.BaseProvider):
    def smth(self):
        return self.random_element([1, 2, 3])

factory.Faker.add_provider(MyProvider)

And set the seed. Although I believe it's poorly documented. And I'm going to file a corresponding issue. I can mention there anybody interested.

x-yuri avatar Jan 04 '21 09:01 x-yuri

The only thing special about the faker in my projects, is setting the locale, adding custom providers, and also setting the faker seed.

Setting the locale: https://github.com/FactoryBoy/factory_boy/issues/407#issuecomment-754281399 https://github.com/FactoryBoy/factory_boy/pull/832

Adding providers: see the previous post.

Setting the seed: https://github.com/FactoryBoy/factory_boy/issues/833

x-yuri avatar Jan 10 '21 09:01 x-yuri

Thank you. This is very useful. Seeing as the other tickets, cover it, I guess this can be closed then?

chriswyatt avatar Jan 11 '21 09:01 chriswyatt