Fill records with names, emails, cities and jobs that look real, and keep a product's sku, title and price together by drawing one row of a CSV file.
Before You Start
The commands run from the root of a clone of the repository, where the files are in docs/snippets/generate-data/. The Full Files block of this page holds the same files, for a reader who saves them by hand.
signups_gap=DistributionConfig(dist="exponential",rate=0.5)# The random sequence the blueprint's draw usessignups_gap.stream="arrival.signups"
Draw Names and Places
A fake field calls one method of the Faker library by name: name, email, city and job here. locale: de_DE draws a field in the German locale, so german_city is a German town. A Faker method that reads today's date, such as date_of_birth, would change the records from day to day, so this model uses none.
signup_payload=Template({"customer_id":{"gen":"sequence","start":1},"name":{"gen":"fake","method":"name"},"email":{"gen":"fake","method":"email"},"city":{"gen":"fake","method":"city"},"german_city":{"gen":"fake","method":"city","locale":"de_DE"},"job":{"gen":"fake","method":"job"},"favourite":{"gen":"row","file":CSV,"weight":"popularity"},},name="tasks.signup",)@app.task(name="signup")defsignup(task_id):"""Gives one signup record."""returnsignup_payload
sampler=Sampler(seed=42)deffaker(place,locale="en_US"):"""A Faker seeded from the random sequence of the generator at `place`."""fake=Faker(locale)fake.seed_instance(int(sampler.generator(place+"#fake").integers(2**32)))returnfakename=faker("tasks.signup.payload.name")email=faker("tasks.signup.payload.email")city=faker("tasks.signup.payload.city")german_city=faker("tasks.signup.payload.german_city","de_DE")job=faker("tasks.signup.payload.job")# A cell of digits is a number, as the `row` generator reads itwithCSV.open(encoding="utf-8")asfile:products:list=[{"sku":row["sku"],"title":row["title"],"price":float(row["price"]),"popularity":int(row["popularity"]),}forrowincsv.DictReader(file)]total=sum(product["popularity"]forproductinproducts)shares=[product["popularity"]/totalforproductinproducts]favourite=sampler.generator("tasks.signup.payload.favourite")
Each fake field has a Faker of its own, seeded from the random sequence named by the field's place with #fake added. The Low-level file builds one Faker for each field in the same way, and a fixed seed gives the same names every run.
Keep a Product Together
row draws one row of a CSV file, so the sku, the title and the price always belong to the same product. weight: popularity draws the rows in proportion to the popularity column, so the notebook, with 12 of the 30 points in the file, is the favourite of 12 customers in 30.
The Builder and Low-level files name the CSV file by a path beside the file, because a Builder row file is read from the working directory. The Low-level file reads the file itself with csv.DictReader and draws a row by its share of the popularity.
Check the Result
Run the model for 20 simulated seconds and print its first 3 records. Each record has a name, an email, a city, a German city, a job and a product.
The names depend on the version of Faker that the lock file pins, so a different version writes other names. The records stay the same from run to run for one version.
# Realistic fields: names, emails and places from Faker, and products from a CSV file.## A customer signs up about every 2 seconds. Their name, email, city and job come# from Faker, one `fake` generator for each field, and `german_city` is a city drawn# in the German locale (`de_DE`). A Faker method that reads today's date would change# the records from day to day, so this file uses none. The product is one row of# realistic_fields_products.csv, chosen by the popularity column, so the sku, title and# price stay together.## Needs: the fake extra.# Run it with: desflow run docs/snippets/generate-data/realistic_fields.yamlsimulation:sim_id:Shopfactor:0random_seed:42logical_start_time:2026-01-01T00:00:00egress:-{type:Console}arrivals:signups:{dist:exponential, rate:0.5, spawn:signup}tasks:signup:payload:customer_id:{gen:sequence, start:1}name:{gen:fake, method:name}email:{gen:fake, method:email}city:{gen:fake, method:city}german_city:{gen:fake, method:city, locale:de_DE}job:{gen:fake, method:job}favourite:{gen:row, file:realistic_fields_products.csv, weight:popularity}run:{until:20}
"""Realistic fields: names, emails and places from Faker, and products from a CSV file.The builder version of `realistic_fields.yaml`: a customer signs up about every 2seconds, with fields from Faker and a product from a CSV file.Needs: the fake extra.Run it with: python docs/snippets/generate-data/realistic_fields_builder.py"""importloggingfromdatetimeimportdatetime,timezonefrompathlibimportPathfromdesflowimportConsoleEgress,SimulationContextfromdesflow.valuesimportTemplateCSV=str(Path(__file__).with_name("realistic_fields_products.csv"))UNTIL=20defbuild()->SimulationContext:"""Builds the model."""app=SimulationContext(sim_id="Shop",factor=0,random_seed=42,logical_start_time=datetime(2026,1,1,tzinfo=timezone.utc),)app.add_egress(ConsoleEgress())app.add_arrival("signups","exponential",rate=0.5,spawn="signup")signup_payload=Template({"customer_id":{"gen":"sequence","start":1},"name":{"gen":"fake","method":"name"},"email":{"gen":"fake","method":"email"},"city":{"gen":"fake","method":"city"},"german_city":{"gen":"fake","method":"city","locale":"de_DE"},"job":{"gen":"fake","method":"job"},"favourite":{"gen":"row","file":CSV,"weight":"popularity"},},name="tasks.signup",)@app.task(name="signup")defsignup(task_id):"""Gives one signup record."""returnsignup_payloadreturnappif__name__=="__main__":logging.basicConfig(level=logging.INFO,format="%(levelname)s%(message)s")build().run(until=UNTIL)
"""Realistic fields: names, emails and places from Faker, and products from a CSV file.The low-level version of `realistic_fields.yaml`: plain SimPy on a`DynamicRealtimeEnvironment`, which publishes each record with `publish_event`. Eachfield has a Faker of its own, seeded from the random sequence the blueprint's generatorat that place uses (its place with `#fake` added), and the product is one row of theCSV file read with the `csv` module, chosen by `Sampler.generator(<place>)` with thepopularity column as the weights.Needs: the fake extra.Run it with: python docs/snippets/generate-data/realistic_fields_low_level.py"""importcsvimportloggingfromdatetimeimportdatetime,timezonefrompathlibimportPathfromfakerimportFakerfromdesflowimport(ConsoleEgress,DistributionConfig,DynamicRealtimeEnvironment,Sampler,)CSV=Path(__file__).with_name("realistic_fields_products.csv")UNTIL=20START=datetime(2026,1,1,tzinfo=timezone.utc)ENVIRONMENT:dict={"logical_start_time":START,"timezone":"UTC"}defbuild(env:DynamicRealtimeEnvironment)->None:"""Starts the arrival on `env`."""sampler=Sampler(seed=42)deffaker(place,locale="en_US"):"""A Faker seeded from the random sequence of the generator at `place`."""fake=Faker(locale)fake.seed_instance(int(sampler.generator(place+"#fake").integers(2**32)))returnfakename=faker("tasks.signup.payload.name")email=faker("tasks.signup.payload.email")city=faker("tasks.signup.payload.city")german_city=faker("tasks.signup.payload.german_city","de_DE")job=faker("tasks.signup.payload.job")# A cell of digits is a number, as the `row` generator reads itwithCSV.open(encoding="utf-8")asfile:products:list=[{"sku":row["sku"],"title":row["title"],"price":float(row["price"]),"popularity":int(row["popularity"]),}forrowincsv.DictReader(file)]total=sum(product["popularity"]forproductinproducts)shares=[product["popularity"]/totalforproductinproducts]favourite=sampler.generator("tasks.signup.payload.favourite")signups_gap=DistributionConfig(dist="exponential",rate=0.5)# The random sequence the blueprint's draw usessignups_gap.stream="arrival.signups"defsignups_source():number=0whileTrue:yieldenv.timeout(sampler.sample(signups_gap))number+=1payload={"customer_id":number,"name":name.name(),"email":email.email(),"city":city.city(),"german_city":german_city.city(),"job":job.job(),"favourite":dict(products[int(favourite.choice(len(products),p=shares))]),}env.publish_event(f"signups-{number}",payload,task="signup",instance=number-1)env.process(signups_source())defrun()->None:"""Runs the model unpaced into the console."""env=DynamicRealtimeEnvironment(factor=0,**ENVIRONMENT)env.setup_egress([ConsoleEgress()])build(env)try:env.run(until=UNTIL)finally:env.teardown()if__name__=="__main__":logging.basicConfig(level=logging.INFO,format="%(levelname)s%(message)s")run()