@@ -222,7 +222,7 @@ def make_cake_templates():
222222 )
223223
224224 for key in tmpl :
225- tmpl [key ].add_uid (TEMPLATE_SCOPE , key )
225+ tmpl [key ].add_uid (TEMPLATE_SCOPE , key . lower (). replace ( ' ' , '-' ) )
226226 return tmpl
227227
228228
@@ -233,21 +233,30 @@ def make_cake_spec(tmpl=None):
233233 if tmpl is None :
234234 tmpl = make_cake_templates ()
235235
236- def _make_ingredient (material , ** kwargs ):
236+ def _make_ingredient (* , material , process , ** kwargs ):
237237 """Convenience method to utilize material fields in creating an ingredient's arguments."""
238238 return IngredientSpec (
239239 name = material .name .lower (),
240240 tags = list (material .tags ),
241241 material = material ,
242+ process = process ,
243+ uids = {DEMO_SCOPE : "{}--{}" .format (material .uids [DEMO_SCOPE ],
244+ process .uids [DEMO_SCOPE ]
245+ )},
242246 ** kwargs
243247 )
244248
245- def _make_material (material_name , process_tmpl_name , process_kwargs , ** material_kwargs ):
249+ def _make_material (* , material_name , template , process_tmpl_name , process_kwargs ,
250+ ** material_kwargs ):
246251 """Convenience method to reuse material name in creating a material's arguments."""
252+ process_name = "{} {}" .format (process_tmpl_name , material_name )
247253 return MaterialSpec (
248254 name = material_name ,
255+ uids = {DEMO_SCOPE : material_name .lower ().replace (' ' , '-' )},
256+ template = template ,
249257 process = ProcessSpec (
250- name = "{} {}" .format (process_tmpl_name , material_name ),
258+ name = process_name ,
259+ uids = {DEMO_SCOPE : process_name .lower ().replace (' ' , '-' )},
251260 template = tmpl [process_tmpl_name ],
252261 ** process_kwargs
253262 ),
@@ -624,6 +633,7 @@ def _make_material(material_name, process_tmpl_name, process_kwargs, **material_
624633 _make_ingredient (
625634 material = eggs ,
626635 labels = ['wet' ],
636+ process = wetmix .process ,
627637 absolute_quantity = NominalReal (nominal = 4 , units = '' )
628638 )
629639
@@ -741,25 +751,6 @@ def _make_material(material_name, process_tmpl_name, process_kwargs, **material_
741751 mass_fraction = NominalReal (nominal = 0.6387 , units = '' ) # 4 c @ 30 g/ 0.25 cups
742752 )
743753
744- # Crawl tree and annotate with uids; only add ids if there's nothing there
745- def _make_fuzzer ():
746- """Generate closure that knows if it's seen a given name."""
747- seen = set ()
748-
749- def _fuzz_func (obj ):
750- """Add fuzz to name in ID as necessary."""
751- name = 'ing-' if isinstance (obj , IngredientSpec ) else ''
752- name += obj .name
753- while name .lower () in seen :
754- name += '-again'
755- seen .add (name .lower ())
756- return name
757-
758- return _fuzz_func
759-
760- _name_fuzz = _make_fuzzer ()
761- recursive_foreach (cake , lambda obj : obj .uids or obj .add_uid (DEMO_SCOPE , _name_fuzz (obj )))
762-
763754 return cake
764755
765756
@@ -770,6 +761,13 @@ def make_cake(seed=None, tmpl=None, cake_spec=None, toothpick_img=None):
770761
771762 if seed is not None :
772763 random .seed (seed )
764+ # Code to generate quasi-repeatable run annotations
765+ # Note there are potential machine dependencies
766+ md5 = hashlib .md5 ()
767+ for x in random .getstate ()[1 ]:
768+ md5 .update (struct .pack (">I" , x ))
769+ run_key = md5 .hexdigest ()
770+
773771 ######################################################################
774772 # Parent Objects
775773 if tmpl is None :
@@ -785,10 +783,13 @@ def make_cake(seed=None, tmpl=None, cake_spec=None, toothpick_img=None):
785783 drygoods = ['Acme' , 'A1' , 'Reliable' , "Big Box" ]
786784 cake .process .source = PerformedSource (performed_by = random .choice (operators ),
787785 performed_date = '2015-03-14' )
788- # Replace Abstract/In General
789- queue = [cake ]
790- while queue :
791- item = queue .pop (0 )
786+
787+ def _randomize_object (item ):
788+ # Add in the randomized particular values
789+ if not isinstance (item , (MaterialRun , ProcessRun , IngredientRun )):
790+ return
791+
792+ item .add_uid (DEMO_SCOPE , '{}-{}' .format (item .spec .uids [DEMO_SCOPE ], run_key ))
792793 if item .spec .tags is not None :
793794 item .tags = list (item .spec .tags )
794795 if item .spec .notes : # Neither None or empty string
@@ -800,17 +801,14 @@ def make_cake(seed=None, tmpl=None, cake_spec=None, toothpick_img=None):
800801 else :
801802 supplier = random .choice (drygoods )
802803 item .name = "{} {}" .format (supplier , item .spec .name )
803- queue .append (item .process )
804- elif isinstance (item , ProcessRun ):
805- queue .extend (item .ingredients )
804+ if isinstance (item , ProcessRun ):
806805 if item .template .name == "Procuring" :
807806 item .source = PerformedSource (performed_by = 'hamilton' ,
808807 performed_date = '2015-02-17' )
809808 item .name = "{} {}" .format (item .template .name , item .output_material .name )
810809 else :
811810 item .source = cake .process .source
812- elif isinstance (item , IngredientRun ):
813- queue .append (item .material )
811+ if isinstance (item , IngredientRun ):
814812 fuzz = 0.95 + 0.1 * random .random ()
815813 if item .spec .absolute_quantity is not None :
816814 item .absolute_quantity = \
@@ -833,9 +831,7 @@ def make_cake(seed=None, tmpl=None, cake_spec=None, toothpick_img=None):
833831 NormalReal (mean = fuzz * item .spec .number_fraction .nominal ,
834832 std = 0.05 * item .spec .number_fraction .nominal ,
835833 units = item .spec .number_fraction .units )
836-
837- else :
838- raise TypeError ("Unexpected object in the queue" )
834+ recursive_foreach (cake , _randomize_object )
839835
840836 frosting = \
841837 next (x .material for x in cake .process .ingredients if 'rosting' in x .name )
@@ -882,9 +878,14 @@ def _find_name(name, material):
882878 )
883879 sugar_content .spec = salt_content .spec
884880
881+ # Note that while specs are regenerated each make_cake invocation, they are all identical
885882 for msr in (cake_taste , cake_appearance , frosting_taste , frosting_sweetness ,
886883 baked_doneness , flour_content , salt_content , sugar_content ):
887- msr .spec .add_uid (DEMO_SCOPE , msr .spec .name )
884+ msr .spec .add_uid (DEMO_SCOPE , msr .spec .name .lower ())
885+ msr .add_uid (DEMO_SCOPE , '{}--{}-{}' .format (msr .spec .uids [DEMO_SCOPE ],
886+ msr .material .spec .uids [DEMO_SCOPE ],
887+ run_key
888+ ))
888889
889890 ######################################################################
890891 # Let's add some attributes
@@ -1029,35 +1030,6 @@ def _find_name(name, material):
10291030 origin = "specified"
10301031 ))
10311032
1032- # Code to generate quasi-repeatable run annotations
1033- # Note there are potential machine dependencies
1034- md5 = hashlib .md5 ()
1035- for x in random .getstate ()[1 ]:
1036- md5 .update (struct .pack (">I" , x ))
1037- run_key = md5 .hexdigest ()
1038-
1039- # Crawl tree and annotate with uids; only add ids if there's nothing there
1040- def _make_disambiguator ():
1041- """Generate a closure to post-annotate for disambiguation."""
1042- count = dict ()
1043-
1044- def _disambiguator (name ):
1045- """Add a number to the name if you've seen it more than once."""
1046- if name in count :
1047- count [name ] = count [name ] + 1
1048- return "{}-{}" .format (name , count [name ])
1049- else :
1050- count [name ] = 1
1051- return name
1052-
1053- return _disambiguator
1054-
1055- _disambig = _make_disambiguator ()
1056- recursive_foreach (
1057- cake ,
1058- lambda obj : obj .uids or obj .add_uid (DEMO_SCOPE , _disambig (obj .name ) + run_key )
1059- )
1060-
10611033 cake .notes = cake .notes + "; Très délicieux! 😀"
10621034 cake .file_links = [FileLink (
10631035 filename = "Photo" ,
0 commit comments